@blandsdk/client

中文文档
1.0.1发布于 2025/10/22MITTypeScriptESM + CJS近 30 天下载 6218

Bland client SDK for Node, React, and Vanilla JS.

原始使用文档
文档目录7 节
  1. Getting Started
  2. Installation
  3. Overview
  4. Usage: Server-Side (Admin SDK)
  5. Usage: Client-Side (Webchat SDK) - React
  6. Client Options
  7. Need Help?

@blandsdk/client

The Bland SDK is a JavaScript/TypeScript SDK for integrating with the Bland platform. It provides both server-side and client-side components to facilitate communication with Bland's services.

npm version npm downloads license

Getting Started

The Bland SDK has two components:

  • Admin SDK: Server-Side SDK for creating sessions, handling authentication, and interacting with Bland using your privileged API key.
  • Client SDK: Webchat SDK for embedding Bland inside your application. Your API key should never be used here.

Installation

npm install @blandsdk/client

Overview

The SDK is designed to be used in both server-side and client-side environments. The server-side component (Admin SDK) is responsible for creating sessions, using a privileged API key to make requests to bland and managing authentication, while the client-side component (Webchat SDK) handles the user interface and interaction with Bland.

Browser Client -> Your Server (which uses the Admin SDK) -> Bland

Then, when the client has a session token:

Browser Client -> Bland

Usage: Server-Side (Admin SDK)

The Admin SDK is used to create sessions for agents. Below is an example of an Express route that creates a session for a given agentId and returns a session token. This token is then used by the Webchat SDK on the client side.

import express from "express";
import bodyParser from "body-parser";
import Bland from "@blandsdk/client";

const app = express();
app.use(bodyParser.json());

const bland = new Bland({
  admin: {
    apiKey: process.env.BLAND_API_KEY,
    endpoint: "https://api.bland.ai" // enterprise users: contact your account executive for the correct endpoint.
  },
  webchat: {}
});

app.post("/api/agent-authorize", async (req, res) => {
  try {
    const agentId = req.body?.agentId;
    if (!agentId) {
      return res.status(400).json({ error: "missing agentId" });
    }

    const admin = await bland.AdminClient();

    const session = await admin.sessions.create({ agentId });

    res.json({ token: session.token });
  } catch (err: any) {
    res.status(500).json({ error: err?.message || "internal error" });
  }
});

const port = 5174;
app.listen(port, () => {
  console.log(`Admin server running on http://localhost:${port}`);
});

Usage: Client-Side (Webchat SDK) - React

Here is a minimal example that requests a session token from your Admin SDK, connects Webchat, listens to events, and shows a transcript. Pair this with the Express route from the Admin section that returns { token } for a given agentId.

import { useEffect, useMemo, useRef, useState } from "react";
import { useWebchat } from "@blandsdk/client/react";

type Token = { token: string };

async function authorizeAgent(agentId: string): Promise<Token> {
  const r = await fetch("<your server url>", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ agentId })
  });
  if (!r.ok) throw new Error(`authorize error ${r.status}`);
  return r.json();
}

export default function App() {
  const [agentId, setAgentId] = useState("abc123");
  const [status, setStatus] = useState("idle");
  const [streamSid, setStreamSid] = useState<string | null>(null);
  const [transcript, setTranscript] = useState<string>("");
  const logRef = useRef<HTMLPreElement | null>(null);

  const getToken = useMemo(() => {
    return async () => authorizeAgent(agentId);
  }, [agentId]);

  const { state, start, stop, webchat } = useWebchat({
    agentId,
    getToken
  });

  useEffect(() => {
    const off = [
      webchat.on("open", () => {
        setStatus("open");
        log("[Websocket][open]");
      }),
      webchat.on("text", (raw: string) => {
        log(`[Websocket][text] ${raw}`);
      }),
      webchat.on("message", (m: any) => {
        log(`[Websocket][message] ${JSON.stringify(m)}`);
        if (!streamSid && m?.streamSid) setStreamSid(m.streamSid);
      }),
      webchat.on("update", (m: any) => {
        log(`[Websocket][update] ${JSON.stringify(m)}`);
        const who = m?.payload?.type === "assistant" ? "assistant" : "human";
        const t = m?.payload?.text;
        if (typeof t === "string" && t.length) {
          setTranscript((cur) => (cur ? `${cur}\n${who}: ${t}` : `${who}: ${t}`));
        }
      }),
      webchat.on("closed", () => {
        setStatus("closed");
        log("[Websocket][closed]");
      }),
      webchat.on("error", (e: unknown) => {
        setStatus("closed");
        log(`[Websocket][error] ${stringify(e)}`);
      })
    ];
    return () => off.forEach((u) => u());
  }, [webchat, streamSid]);

  function stringify(v: unknown) {
    try { return typeof v === "string" ? v : JSON.stringify(v) } catch { return String(v) }
  }

  function log(line: string) {
    const ts = new Date().toISOString();
    if (logRef.current) {
      logRef.current.textContent += `[${ts}] ${line}\n`;
      logRef.current.scrollTop = logRef.current.scrollHeight;
    }
  }

  const onStart = async () => {
    try {
      setStatus("authorizing");
      await start();
    } catch (e) {
      setStatus("closed");
      log(String(e));
    }
  };

  const onStop = () => {
    try { stop() } finally { setStatus("closed") }
  };

  return (
    <div style={{ maxWidth: 760, margin: "0 auto", padding: 24, fontFamily: "system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif" }}>
      <h1 style={{ fontSize: 22, margin: "0 0 16px" }}>Bland React SDK</h1>
      <div style={{ display: "flex", gap: 8, alignItems: "center", margin: "12px 0" }}>
        <label htmlFor="agent">Agent</label>
        <input id="agent" value={agentId} onChange={(e) => setAgentId(e.target.value)} />
        <button onClick={onStart} disabled={state !== "closed" && state !== "connecting"}>Start</button>
        <button onClick={onStop} disabled={state === "closed"}>Stop</button>
      </div>
      <div style={{ padding: "8px 10px", background: "#f5f5f5", borderRadius: 6, marginTop: 12 }}>{status}</div>
      <h2 style={{ fontSize: 16, marginTop: 16 }}>Transcript</h2>
      <pre style={{ whiteSpace: "pre-wrap", background: "#fafafa", padding: 12, borderRadius: 6 }}>{transcript}</pre>
      <h2 style={{ fontSize: 16, marginTop: 16 }}>Log</h2>
      <pre ref={logRef} style={{ whiteSpace: "pre-wrap", background: "#0b1020", color: "#e6edf3", padding: 12, borderRadius: 6, maxHeight: 300, overflow: "auto" }} />
    </div>
  );
}

Client Options

export interface BlandClientOptions {
    admin: {
        apiKey?: string;
        endpoint?: string;
    }
    webchat?: {
        endpoint?: string;
    }
}

Need Help?

Join our discord for support! Our docs are also available here.

版本与发布记录

@blandsdk/client 共发布 2 个版本,首次发布于 2025/09/16;过去 12 个月发布了 0 个版本。

版本发布日期距今
1.0.1latest2025/10/221 年前
1.0.02025/09/161.1 年前

关于 @blandsdk/client 的常见问题

@blandsdk/client 是什么?

Bland client SDK for Node, React, and Vanilla JS.

如何安装 @blandsdk/client?

在项目目录运行 npm install @blandsdk/client,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=18)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@blandsdk/client 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@blandsdk/client 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@blandsdk/client 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@blandsdk/client 可以商用吗?

@blandsdk/client 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@blandsdk/client 的下载量有多少?

根据 npm 官方下载统计,@blandsdk/client 在 2026/10/09 – 2026/11/07 这 30 天内被下载 6,218 次,日均约 207 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@blandsdk/client 还在维护吗?

最新版本 1.0.1 发布于 2025/10/22(1 年前);至今共发布 2 个版本,其中过去 12 个月发布了 0 个;首次发布于 2025/09/16。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。