{"id":2613,"date":"2019-03-06T02:03:32","date_gmt":"2019-03-06T02:03:32","guid":{"rendered":"https:\/\/developer.microsoft.com\/en-us\/office\/blogs\/?p=2613"},"modified":"2019-03-06T02:03:32","modified_gmt":"2019-03-06T02:03:32","slug":"preview-release-of-the-node-js-bot-builder-v4-sdk-for-microsoft-teams","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/preview-release-of-the-node-js-bot-builder-v4-sdk-for-microsoft-teams\/","title":{"rendered":"Preview release of the Node.js Bot Builder v4 SDK for Microsoft Teams"},"content":{"rendered":"<p>We\u2019re excited to announce the preview release of the\u00a0<a style=\"background-color: #ffffff;color: #0067b8;text-decoration: underline\" href=\"https:\/\/github.com\/OfficeDev\/BotBuilder-MicrosoftTeams-node\" target=\"_blank\" rel=\"noopener noreferrer\">Node.js Teams Bot Builder v4 SDK<\/a>. This has consistently been a top ask from our bot builders and we\u2019re very happy to begin expanding our support for bots built on Bot Framework to include the newest version. This preview release is just the beginning; over the next few months we\u2019ll be adding new documentation, samples and releasing our SDKs for both .NET and Node.js.<\/p>\n<h3>A brief introduction to Bot Framework v4 for Node.js<\/h3>\n<p>First and foremost, its important to realize that everything you can do in Bot Framework v4, you can do in v3 (and vice-versa), it&#8217;s just different. If you haven&#8217;t worked with Bot Framework v4 I highly recommend reading through the <a title=\"How Bots Work\" href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/bot-service\/bot-builder-basics?view=azure-bot-service-4.0&amp;tabs=cs\" target=\"_blank\" rel=\"noopener noreferrer\">Concept<\/a> section of their documentation. You&#8217;ll get a great introduction to the platform, how it is structured, and what pieces you&#8217;ll need to focus on as you design your bot.<\/p>\n<p>The core concept underlying Bot Framework is the idea of a\u00a0<em>turn<\/em>, which represents a complete question-and-response interaction with your bot. The below diagram shows a typical interaction with your bot. You receive an HTTP Post message containing JSON from the client. The Adapter creates an Activity object, initiates the OnTurn pipeline and passes the Activity to any middleware you&#8217;ve registered. After performing it&#8217;s logic, the middleware passes the Activity to your bot to perform your OnTurn logic, and if necessary you read\/write to your state through a state property accessor. Once your logic finishes the Activity is handed back to the middleware for any final processing, and finally your response is returned to the client.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-2457\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2019\/01\/BotInformationFlow.png\" alt=\"\" width=\"869\" height=\"534\" srcset=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2019\/01\/BotInformationFlow.png 869w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2019\/01\/BotInformationFlow-300x184.png 300w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2019\/01\/BotInformationFlow-768x472.png 768w\" sizes=\"(max-width: 869px) 100vw, 869px\" \/><\/p>\n<h3>Overview of the Microsoft Teams Bot Builder SDK for Node.js<\/h3>\n<p>Our SDK extends the core Bot Builder SDK with Microsoft Teams specific functionality allowing you to create a rich experiences for your users. In addition to adding Teams specific extensions to the Bot Builder libraries (TeamsActivityProcessor, TeamsAdapter and TeamsConnectorClient), we add four middleware classes and a Teams-specific conversation state.<\/p>\n<ul>\n<li>TeamsMiddleware &#8211; This is the core middleware that creates a TeamContext object which adds Teams specific information to the Activity.<\/li>\n<li>DropChannelActivitiesMiddleware &amp; DropChatActivitiesMiddleware\u00a0&#8211; Both allow you to restrict interactions to a particular kind of channel. For example, if your bot doesn&#8217;t support one-on-one chat you can drop all chat activities.<\/li>\n<li>DropNonTeamsActivitiesMiddleware\u00a0&#8211; Allows you to short-circuit the OnTurn pipeline if the activity didn&#8217;t originate from Teams<\/li>\n<li>TeamSpecificConversationState\u00a0&#8211; This allows you to make use of a state storage accessor that is scoped across an entire Team (two separate interactions with your bot from two members of the same Team can access the same bot state)<\/li>\n<\/ul>\n<h3>Getting Started with the Microsoft Teams Bot Builder SDK for Node.js<\/h3>\n<p>We&#8217;ll be using the EchoBot scaffold provided by Bot Framework. You can find the full quickstart <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/bot-service\/javascript\/bot-builder-javascript-quickstart?view=azure-bot-service-4.0\">here<\/a>.<\/p>\n<ol>\n<li>Open a terminal or elevated command prompt<\/li>\n<li>Change to a clean working directory<\/li>\n<li>Run the following commands<\/li>\n<\/ol>\n<blockquote><p>npm install -g yo generator-botbuilder<\/p>\n<p>yo botbuilder<\/p><\/blockquote>\n<p>Yeoman will prompt you for some information, make sure you choose TypeScript for the language, and the Echo template.<\/p>\n<p>Next, you&#8217;ll need to install the Microsoft Teams Bot Builder SDK for Node.js package.<\/p>\n<blockquote><p>npm install botbuilder-teams@4.0.0-beta1<\/p><\/blockquote>\n<p>In the <strong>index.ts<\/strong> file we&#8217;ll import the teams SDK, update the adapter constant to use a TeamsAdapter, and wire up the TeamsMiddleware:<\/p>\n<blockquote><p>import * as teams from &#8216;botbuilder&#8217;<\/p>\n<p>&#8230;<\/p>\n<div>\n<div>const adapter = new teams.TeamsAdapter({<\/div>\n<div>\u00a0\u00a0\u00a0 appId: endpointConfig.appId || process.env.microsoftAppID,<\/div>\n<div>\u00a0\u00a0\u00a0 appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword,<\/div>\n<div>});<\/div>\n<\/div>\n<div>adapter.use(new teams.TeamsMiddleware());<\/div>\n<\/blockquote>\n<div>\n<div>In the <strong>bot.ts<\/strong> file we&#8217;ll add the import statement and modify the <strong>onTurn\u00a0<\/strong>method to add some Teams-specific information to the response based on what the user says to the bot.<\/div>\n<blockquote>\n<div>\n<div>\n<div>import { ActivityTypes, TurnContext, Activity } from &#8216;botbuilder&#8217;;<\/div>\n<div>import * as teams from &#8216;botbuilder-teams&#8217;;<\/div>\n<div>export class MyBot {<\/div>\n<div>\u00a0\u00a0\u00a0 private readonly activityProcessor = new teams.TeamsActivityProcessor();<\/div>\n<\/div>\n<div>\n<div>\n<div>\u00a0 \u00a0 constructor(){<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 this.setupHandlers();<\/div>\n<div>\u00a0 \u00a0 }<\/div>\n<\/div>\n<\/div>\n<div>\n<div>\n<div>\n<div>\u00a0\u00a0\u00a0 public async onTurn(turnContext: TurnContext) {<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (turnContext.activity.type === ActivityTypes.Message) {<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await this.activityProcessor.processIncomingActivity(turnContext);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } else {<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await turnContext.sendActivity(`[${ turnContext.activity.type } event detected]`);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/div>\n<div>\u00a0\u00a0\u00a0 }<\/div>\n<\/div>\n<\/div>\n<div>\u00a0\u00a0\u00a0 private setupHandlers () {<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 this.activityProcessor.messageActivityHandler = {<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 onMessage: async (ctx: TurnContext) =&gt; {<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const teamsContext = teams.TeamsContext.from(ctx);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const text = teamsContext.getActivityTextWithoutMentions();<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const adapter = ctx.adapter as teams.TeamsAdapter;<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 switch (text.toLowerCase()) {<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case &#8216;reply-chain&#8217;:<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await adapter.createReplyChain(ctx, [{ text: &#8216;New reply chain&#8217; }]);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case &#8216;1:1&#8217;:<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ create 1:1 conversation<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const tenantId = teamsContext.tenant.id;<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const ref = TurnContext.getConversationReference(ctx.activity);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await adapter.createTeamsConversation(ref, tenantId, async (newCtx) =&gt; {<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await newCtx.sendActivity(`Hi (in private)`);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;<\/div>\n<div><\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case &#8216;members&#8217;:<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const members = await adapter.getConversationMembers(ctx);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const actMembers = await adapter.getActivityMembers(ctx);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await ctx.sendActivity({<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 textFormat: &#8216;xml&#8217;,<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 text: `<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;b&gt;Activity Members&lt;\/b&gt;&lt;\/br&gt;<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;pre&gt;${JSON.stringify(actMembers, null, 2)}&lt;\/pre&gt;<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;b&gt;Conversation Members&lt;\/b&gt;&lt;\/br&gt;<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;pre&gt;${JSON.stringify(members, null, 2)}&lt;\/pre&gt;<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 `});<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;<\/div>\n<div><\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case &#8216;team-info&#8217;:<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const teamId = teamsContext.team.id;<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const chList = await teamsContext.teamsConnectorClient.teams.fetchChannelList(teamId);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 const tmDetails = await teamsContext.teamsConnectorClient.teams.fetchTeamDetails(teamId);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await ctx.sendActivity({ textFormat: &#8216;xml&#8217;, text: `&lt;pre&gt;${JSON.stringify(chList, null, 2)}&lt;\/pre&gt;`});<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await ctx.sendActivity({ textFormat: &#8216;xml&#8217;, text: `&lt;pre&gt;${JSON.stringify(tmDetails, null, 2)}&lt;\/pre&gt;`});<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 default:<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 let activity: Partial&lt;Activity&gt; = {<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 textFormat: &#8216;xml&#8217;,<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 text: `You said &#8220;${ ctx.activity.text }&#8221;`<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 };<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 activity = teams.TeamsContext.notifyUser(activity as Activity);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await ctx.sendActivity(activity);<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/div>\n<div>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 };<\/div>\n<div>\u00a0\u00a0\u00a0 }<\/div>\n<div>}<\/div>\n<\/div>\n<\/div>\n<\/blockquote>\n<div>\n<div>\n<div>To deploy and test your bot, you can use App Studio to register a new bot with Bot Framework and create a manifest file. Once you&#8217;ve got a bot Id and Password you&#8217;ll need to add them to the &lt;botname&gt;.bot file, as well as update the endpoint (if you&#8217;re working locally you&#8217;ll need to use a tunneling service like ngrok to get a publicly facing URL to use). You can find detailed instructions on how to do this in <a href=\"https:\/\/docs.microsoft.com\/en-us\/microsoftteams\/platform\/resources\/general\/debug\">our documentation<\/a>.<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3>Additional resources<\/h3>\n<ul>\n<li>Full sample TeamsBot app on GitHub:<a href=\"https:\/\/github.com\/OfficeDev\/BotBuilder-MicrosoftTeams-node\/tree\/master\/samples\/teams-bot\">https:\/\/github.com\/OfficeDev\/BotBuilder-MicrosoftTeams-node\/tree\/master\/samples\/teams-bot<\/a><\/li>\n<li>The GitHub repository for our SDK (including additional samples):\u00a0<a href=\"https:\/\/github.com\/OfficeDev\/BotBuilder-MicrosoftTeams-node\">https:\/\/github.com\/OfficeDev\/BotBuilder-MicrosoftTeams-node<\/a><\/li>\n<li>The Bot Framework documentation:\u00a0<a href=\"https:\/\/aka.ms\/botframeworkdocs\" target=\"_self\" rel=\"noopener noreferrer\">https:\/\/aka.ms\/botframeworkdocs<\/a><\/li>\n<li>A large repository of Bot Framework bots (not Teams samples) <a href=\"https:\/\/aka.ms\/botbuildersamples\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/aka.ms\/botbuildersamples<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>We\u2019re excited to announce the preview release of the Node.js Teams Bot Builder v4 SDK. This has consistently been a top ask from our bot builders and we\u2019re very happy to begin expanding our support for bots built on Bot Framework to include the newest version. This preview release is just the beginning; over the next few months we\u2019ll be adding new documentation, samples and releasing our SDKs for both .NET and Node.js.<\/p>\n","protected":false},"author":69074,"featured_media":25159,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[128],"tags":[37],"class_list":["post-2613","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-teams","tag-bot-framework"],"acf":[],"blog_post_summary":"<p>We\u2019re excited to announce the preview release of the Node.js Teams Bot Builder v4 SDK. This has consistently been a top ask from our bot builders and we\u2019re very happy to begin expanding our support for bots built on Bot Framework to include the newest version. This preview release is just the beginning; over the next few months we\u2019ll be adding new documentation, samples and releasing our SDKs for both .NET and Node.js.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/2613","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/users\/69074"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/comments?post=2613"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/2613\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media\/25159"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media?parent=2613"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/categories?post=2613"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/tags?post=2613"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}