{"id":10587,"library":"botframework-directlinejs","title":"Microsoft Bot Framework Direct Line JS Client","description":"This package provides a client library for the Microsoft Bot Framework Direct Line 3.0 protocol, enabling JavaScript applications to communicate directly with bots. It is an official Microsoft-supported library, used internally by components like BotFramework-WebChat, the Bot Framework Emulator, and Azure Bot Service. The current stable version is 0.15.8. The library primarily uses RxJS Observables for handling asynchronous operations, a key differentiator from Promise-based alternatives. While considered largely complete for its protocol, updates are typically limited to dependency bumps, bug fixes, and minor enhancements rather than new feature development, indicating a maintenance-focused release cadence. It fully supports TypeScript.","status":"active","version":"0.15.8","language":"javascript","source_language":"en","source_url":"https://github.com/microsoft/BotFramework-DirectLineJS","tags":["javascript","typescript"],"install":[{"cmd":"npm install botframework-directlinejs","lang":"bash","label":"npm"},{"cmd":"yarn add botframework-directlinejs","lang":"bash","label":"yarn"},{"cmd":"pnpm add botframework-directlinejs","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Provides streaming capabilities for the Direct Line Streaming protocol, handling real-time communication with the bot backend.","package":"botframework-streaming"},{"reason":"Offers runtime helpers for Babel-compiled code, a common peer dependency in modern JavaScript projects.","package":"@babel/runtime"},{"reason":"Ensures a consistent `fetch` API for making HTTP requests across various JavaScript environments, including Node.js and browsers.","package":"cross-fetch"},{"reason":"Core dependency for Observable-based asynchronous programming, which this library extensively uses for handling activity streams and connection status.","package":"rxjs"}],"imports":[{"note":"The library primarily uses ES Modules. Named imports are the standard. CommonJS `require()` is not officially supported for modern usage and may lead to issues.","wrong":"const DirectLine = require('botframework-directlinejs');","symbol":"DirectLine","correct":"import { DirectLine } from 'botframework-directlinejs';"},{"note":"ConnectionStatus is a named enum export. Attempting a default import will fail.","wrong":"import ConnectionStatus from 'botframework-directlinejs';","symbol":"ConnectionStatus","correct":"import { ConnectionStatus } from 'botframework-directlinejs';"},{"note":"Imports the TypeScript interface or type definition for an Activity, which is crucial for type-checking when sending or receiving messages. While not a runnable class, it's a fundamental type.","symbol":"Activity","correct":"import { Activity } from 'botframework-directlinejs';"}],"quickstart":{"code":"import { DirectLine, ConnectionStatus, Activity } from 'botframework-directlinejs';\nimport { filter } from 'rxjs/operators';\n\n// In a real application, retrieve this securely (e.g., from an environment variable or a server-side call)\nconst DIRECT_LINE_SECRET = process.env.DIRECT_LINE_SECRET ?? 'YOUR_DIRECT_LINE_SECRET_HERE';\nconst USER_ID = 'user123'; // A unique user ID for the conversation\n\nconsole.log('Starting Direct Line client...');\n\nconst directLine = new DirectLine({\n  secret: DIRECT_LINE_SECRET, // For production, exchange secret for a token via a backend service\n  webSocket: true, // Use Web Sockets for real-time communication\n  // token: 'YOUR_DIRECT_LINE_TOKEN_HERE' // Recommended for production\n});\n\n// Observe connection status changes\ndirectLine.connectionStatus$.subscribe(connectionStatus => {\n  const statusMessage = ConnectionStatus[connectionStatus];\n  console.log(`Connection status: ${statusMessage}`);\n  if (connectionStatus === ConnectionStatus.Uninitialized) {\n    console.warn('Direct Line connection is uninitialized. Check your secret/token.');\n  } else if (connectionStatus === ConnectionStatus.ExpiredToken) {\n    console.error('Direct Line token expired. Reconnect with a new token.'); //\n  }\n});\n\n// Subscribe to incoming activities from the bot\nconst activitySubscription = directLine.activity$\n  .pipe(\n    filter(activity => activity.type === 'message' && activity.from.id !== USER_ID)\n  )\n  .subscribe(activity => {\n    console.log(`Received activity from bot:`);\n    console.log(JSON.stringify(activity, null, 2));\n\n    if (activity.text && activity.text.toLowerCase().includes('hello')) {\n      console.log('Bot greeted us back!');\n    }\n  }, error => {\n    console.error('Error receiving activities:', error);\n  });\n\n// Send a message to the bot after a brief delay\nsetTimeout(() => {\n  const message: Activity = {\n    from: { id: USER_ID, name: 'Test User' },\n    type: 'message',\n    text: 'Hello bot!',\n    channelData: { clientActivityID: Date.now().toString() } // Unique ID for client activity\n  };\n\n  directLine.postActivity(message).subscribe(\n    id => console.log(`Sent activity with ID: ${id}`),\n    error => console.error('Error sending activity:', error)\n  );\n}, 3000);\n\n// Disconnect after some time (e.g., when the user leaves the chat)\nsetTimeout(() => {\n  console.log('Ending conversation and disconnecting...');\n  activitySubscription.unsubscribe();\n  directLine.end(); // Clean up Direct Line connection\n}, 15000); // Disconnect after 15 seconds for this example","lang":"typescript","description":"This example demonstrates how to initialize the Direct Line client, monitor its connection status, receive messages from a bot using RxJS Observables, and send a message to the bot. It highlights secure token handling and proper cleanup."},"warnings":[{"fix":"Familiarize yourself with RxJS basics, especially `subscribe`, `pipe`, and common operators like `filter` and `map`.","message":"The library utilizes RxJS Observables for all asynchronous operations (e.g., `activity$`, `connectionStatus$`). Developers unfamiliar with RxJS may encounter difficulties when expecting Promise-based or callback-style asynchronous patterns.","severity":"gotcha","affected_versions":">=0.11.0"},{"fix":"Implement the `networkInformation` option by providing a polyfill for the W3C Network Information API, which should include a `type` property and a `change` event. A common approach involves using Server-Sent Events to detect network status changes.","message":"On iOS/iPadOS 15+, the `WebSocket` object may stall without errors when the network changes (e.g., Wi-Fi to cellular) due to an experimental 'NSURLSession WebSocket' feature. This prevents the library from detecting disconnections automatically.","severity":"gotcha","affected_versions":">=0.14.0"},{"fix":"Always exchange the Direct Line secret for a short-lived token on a secure backend server and pass only the token to your client application. The `DirectLine` constructor supports both `secret` and `token` options.","message":"Direct Line secrets should *never* be exposed in client-side code for production applications. They grant full access to your bot's Direct Line channel.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure your build tooling and import paths are updated to use the standard `/lib/` directory for ES modules and TypeScript definitions, or the lowercase `/dist/directline.js` for bundles if still relying on older UMD/CJS distribution.","message":"Older versions of the library, particularly before 0.11.5, used different build output directories (`/dist/directLine.js` vs `/dist/directline.js`). While recent versions standardize `/lib/` for ESM and types, older client code might expect specific paths.","severity":"deprecated","affected_versions":"<0.11.5"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure you call `.subscribe()` on the Observable to initiate the stream and receive values. Example: `directLine.activity$.subscribe(activity => { /* handle activity */ });`","cause":"Attempting to use `activity$` or `connectionStatus$` as a Promise or regular value, when they are RxJS Observables.","error":"TypeError: Cannot read properties of undefined (reading 'subscribe')"},{"fix":"When `connectionStatus$` reports `ConnectionStatus.ExpiredToken`, your application should request a new token from your backend service and re-initialize or reconnect the `DirectLine` object with the fresh token.","cause":"The authentication token used to establish the Direct Line connection has become invalid or has expired.","error":"DirectLine error: token expired."},{"fix":"Verify that your `secret` or `token` is correct and active. If using a secret, ensure it hasn't been revoked. Check network connectivity and firewall rules. For production, always use a generated token from a secure backend.","cause":"Often indicates an invalid or expired Direct Line secret/token, or a network issue preventing the initial WebSocket handshake.","error":"WebSocket connection to 'wss://directline.botframework.com/v3/directline/conversations/...' failed: WebSocket is closed before the connection is established."},{"fix":"Implement the `networkInformation` polyfill to detect network changes and proactively manage the Direct Line connection. Reloading the page or re-initializing DirectLine may temporarily resolve it.","cause":"The device's WebSocket connection silently stalls without error, as detailed in the `networkInformation` warning.","error":"Silent message loss or unresponsive bot on iOS/iPadOS after network changes."}],"ecosystem":"npm"}