npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@streamcore/js-sdk

v0.1.8

Published

Framework-agnostic SDK for connecting to a Pion Voice Agent server via WebRTC + WHIP

Readme

@streamcore/js-sdk

English | 简体中文

框架无关的 TypeScript SDK,通过 WebRTC + WHIP 连接 StreamCoreAI 服务端。

安装

npm install @streamcore/js-sdk

快速开始

import { StreamCoreAIClient } from "@streamcore/js-sdk";

const agent = new StreamCoreAIClient(
  { whipUrl: "http://localhost:8080/whip" },
  {
    onStatusChange: (status) => console.log("Status:", status),
    onTranscript: (entry, all) => console.log("Transcript:", entry),
    onAudioLevel: (level) => console.log("Audio level:", level),
    onAgentStateChange: (state) => console.log("Agent:", state),
    onError: (err) => console.error("Error:", err),
  }
);

// Connect (requests microphone permission, establishes WebRTC session)
await agent.connect();

// Mute / unmute
agent.toggleMute();
console.log("Muted:", agent.isMuted);

// Disconnect
agent.disconnect();

API

new StreamCoreAIClient(config?, events?)

创建一个新的客户端实例。

StreamCoreAIConfig

| 属性 | 类型 | 默认值 | 说明 | | ------------------ | ---------------------- | ------------------------------------ | ------------------------------------ | | whipUrl | string | "http://localhost:8080/whip" | WHIP 信令端点 URL | | token | string | — | 预先获取的 JWT,在 WHIP 请求中以 Authorization: Bearer 发送 | | tokenUrl | string | — | connect() 期间 SDK POST 获取短时效 token 的端点 | | apiKey | string | — | 调用 tokenUrl 时以 Authorization: Bearer 发送 | | iceServers | RTCIceServer[] | [{ urls: "stun:stun.l.google.com:19302" }] | ICE 服务器配置 | | audioConstraints | MediaTrackConstraints| { echoCancellation: true, noiseSuppression: true, autoGainControl: true, voiceIsolation: true, channelCount: 1 } | 麦克风约束 |

StreamCoreAIEvents

| 事件 | 签名 | 说明 | | -------------------- | ------------------------------------------------------ | ---------------------------------- | | onStatusChange | (status: ConnectionStatus) => void | 连接状态变化时触发 | | onTranscript | (entry: TranscriptEntry, all: TranscriptEntry[]) => void | 有新的或更新的转写时触发 | | onAudioLevel | (level: number) => void | 每一帧动画触发一次,携带麦克风电平(0–1) | | onAgentStateChange | (state: AgentState) => void | 智能体开始聆听、思考或说话时触发 | | onError | (error: Error) => void | 连接或服务端错误时触发 | | onTiming | (event: TimingEvent) => void | 携带服务端流水线耗时信息 | | onDataChannelMessage | (message: DataChannelMessage) => void | 每条原始 DataChannel 消息都会触发,早于各类型化回调 | | onData | (topic: string, payload: Uint8Array) => void | 服务端下发的单向数据包,payload 已完成 base64 解码(car.command 承载传动指令) |

实例方法

| 方法 | 返回值 | 说明 | | --------------- | --------------- | ------------------------------------------------- | | connect() | Promise<void> | 请求麦克风权限,建立 WebRTC + WHIP 会话 | | disconnect() | void | 拆除连接、停止麦克风、释放资源 | | toggleMute() | void | 切换麦克风静音 | | on(event, fn) | void | 在构造之后注册事件监听器 |

实例属性(只读)

| 属性 | 类型 | 说明 | | ------------ | -------------------- | ------------------------------------ | | status | ConnectionStatus | "idle" \| "connecting" \| "connected" \| "error" \| "disconnected" | | transcript | TranscriptEntry[] | 完整对话历史 | | audioLevel | number | 当前麦克风音频电平(0–1) | | isMuted | boolean | 麦克风是否静音 | | localStream| MediaStream \| null | 本地麦克风流(connect 之后) | | remoteStream| MediaStream \| null| 远端智能体音频流(connect 之后) |

类型

type ConnectionStatus = "idle" | "connecting" | "connected" | "error" | "disconnected";

type AgentState = "listening" | "thinking" | "speaking";

interface TranscriptEntry {
  role: "user" | "assistant";
  text: string;
  partial?: boolean;
}

interface TimingEvent {
  stage: string;
  ms: number;
}

type DataChannelMessage =
  | { type: "transcript"; text: string; final: boolean }
  | { type: "response"; text: string }
  | { type: "error"; message: string }
  | { type: "timing"; stage: string; ms: number }
  | { type: "state"; state: AgentState };

底层辅助函数

包中也导出了原始的 WHIP 调用,便于构建自定义客户端:

import { whipOffer, whipDelete } from "@streamcore/js-sdk";

const { answerSDP, sessionURL } = await whipOffer(whipUrl, offerSDP, token?);
await whipDelete(sessionURL, token?);

大多数应用应改用 StreamCoreAIClient —— 它会处理 peer 建立、ICE 收集、events DataChannel、音频电平计量和拆除。

鉴权

当服务端设置了 jwt_secret 时,/whip 需要 bearer token。不要把服务商 API key 放进浏览器 —— 它们属于服务端的 config.toml。正确做法是让客户端去取一个短时效 token:

const agent = new StreamCoreAIClient({
  whipUrl: "https://agent.example.com/whip",
  tokenUrl: "https://api.example.com/agent-token",
  apiKey: process.env.NEXT_PUBLIC_APP_KEY,
});

connect() 期间,SDK 会 POSTtokenUrl(若提供了 apiKey 则作为 bearer token 发送),并期望返回 { "token": "..." }。如果同时设置了 tokentokenUrl,以 tokenUrl 为准。token 会被缓存,以便 disconnect() 能对 WHIP DELETE 完成鉴权。

通话方身份

如果你使用外部 agent,并希望它跨多次通话记住同一个用户,它就需要知道来的是谁。本 SDK 没有 resourceId 选项,这是刻意的——浏览器自报身份,等于任何人在 devtools 里改一行就能冒充别人。

请改为在支撑 tokenUrl服务端设置。那个端点本来就知道当前登录的是哪个用户,而且它持有 StreamCore /token 所需的 API key:

// 你的后端,POST /agent-token
const res = await fetch("https://agent.example.com/token", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${process.env.STREAMCORE_API_KEY}`,
  },
  body: JSON.stringify({ resource_id: session.user.id }),
});
return Response.json(await res.json()); // { token } —— 再交给浏览器

StreamCore 会把该身份签进 token,之后在每一轮对话中以 resource_id 转发给你的 agent。参见协议 → 通话方身份自带 agent

从源码构建

cd typescript-sdk
npm install
npm run build

编译产物输出到 dist/

配合打包工具使用

SDK 以 ES module 形式发布并附带 TypeScript 声明文件。它在 Vite、webpack、Next.js、esbuild 及其他现代打包工具中开箱即用。

许可证

Apache 2.0