# @anycable/serverless-js 中文文档

规范地址：https://npmcn.com/package/%40anycable/serverless-js/

版本：0\.2\.3
npm 元数据更新时间：2026-08-14T18:15:37.860Z
中文译文更新时间：2026-11-06T07:48:46.069Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40anycable/serverless-js
原文对照：https://npmcn.com/package/%40anycable/serverless-js/?lang=original
项目主页：https://anycable.io/
源码仓库：https://github.com/anycable/anycable-serverless-js

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：39.8 kB，26 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=18\.0\.0
- 运行依赖：1 个
- 首次发布：2023-09-22T02:32:13.283Z
- 最新版本发布：2026-08-14T18:15:37.676Z
- 近 30 天下载量：11609（2026-10-06 至 2026-11-04，npm 官方下载统计）
- 已发布版本数：8（近 12 个月 2 个）

## 中文简介

无服务器 JS 应用程序的任何有线频道

## 安装

```sh
npm install @anycable/serverless-js
```

也可以使用：`pnpm add @anycable/serverless-js`、`yarn add @anycable/serverless-js`、`bun add @anycable/serverless-js`

## README

[![npm version](https://badge.fury.io/js/@anycable%2Fserverless-js.svg)](https://badge.fury.io/js/@anycable%2Fserverless-js)

# 无线服务器

此软件包提供了执行模块 [任何有线](https://anycable.io/) 在无服务器的Node.js环境中执行后端 API. 当然,还有服务器应用软件

> 看我们的 [演示应用程序](https://github.com/anycable/vercel-anycable-demo) 以实例为例.

## 结构和组成部分

该软件包提供功能,从JS/TS后端应用程序中与AnyCable服务器合作,并包括支持以下功能:

-   [JWT 认证](https://npmcn.com/package/%40anycable/serverless-js/#readme-using-anycable-jwt)
-   [已签名流](https://npmcn.com/package/%40anycable/serverless-js/#readme-signed-streams)
-   [广播](https://npmcn.com/package/%40anycable/serverless-js/#readme-broadcasting)

软件包也与 HTTP 处理器一起处理 [任意有线 RPC- over- HTTP](https://docs.anycable.io/anycable-go/rpc) 请求和提供 **频道** 财务报告和审定财务报表 **应用程序** 用于描述您的应用程序的实时特性的抽象 .

## 使用量

安装 `@anycable/serverless-js` 使用您选择的工具的软件包,例如:

```sh
npm install @anycable/serverless-js
```

### 使用任何有线JWT

[任何有线JWT](https://docs.anycable.io/anycable-go/jwt_identification) 是一种推荐的认证客户的方法。 要启动,您可以使用标识对象并用它生成认证符:

```js
import { identificator } from "@anycable/serverless-js";

const jwtSecret = "very-secret";
const jwtTTL = "1h";

export const identifier = identificator(jwtSecret, jwtTTL);

// Then, somewhere in your code, generate a token and provide it to the client
const userId = authenticatedUser.id;
const token = await identifier.generateToken({ userId });

const cableURL = `${CABLE_URL}?jid=${token}`
```

您可以将任何身份证明信息传递给代币. 以后可以用来 _频道_ (见下文).

### 已签名流

您可以创建 _签名_ 实例生成签名的流名,并使用 [任何有线酒吧/分店](https://docs.anycable.io/anycable-go/signed_streams)数字 :

```js
import { signer } from "@anycable/serverless-js";

const streamsSecret = process.env.ANYCABLE_STREAMS_SECRET;

const sign = signer(secret);

const signedStreamName = sign("room/13");
```

然后,您可以与客户端使用生成的流名(使用 [任何有线JS客户端 SDK](https://github.com/anycable/anycable-client):

```js
import { createCable } from "@anycable/web";

const cable = createCable(WEBSOCKET_URL);
const stream = await fetchStreamForRoom("13");

const channel = cable.streamFromSigned(stream);
channel.on("message", (msg) => {
  // handle notification
})
```

### 广播

改为: **广播** 向连接的客户端发送消息,您必须使用广播机实例 :

```js
import { broadcaster } from "@anycable/serverless-js";

// Broadcasting configuration
const broadcastURL =
  process.env.ANYCABLE_BROADCAST_URL || "http://127.0.0.1:8090/_broadcast";
const broadcastToken = process.env.ANYCABLE_HTTP_BROADCAST_SECRET || "";

// Create a broadcasting function to send broadcast messages via HTTP API
export const broadcastTo = broadcaster(broadcastURL, broadcastToken);
```

当AnyCable以单一的应用秘密运行时(`ANYCABLE_SECRET`),广播终点由从该秘密衍生出来的密钥保护. 使用 `broadcastKey` 函数以获取它:

```js
import { broadcaster, broadcastKey } from "@anycable/serverless-js";

export const broadcastTo = broadcaster(
  broadcastURL,
  broadcastKey(process.env.ANYCABLE_SECRET)
);
```

目前,这个软件包只支持通过HTTP进行广播. 然而,AnyCable提供不同的 [广播适配器](https://docs.anycable.io/anycable-go/broadcasting) (如Redis,NATS等),可以融入自己.

### 使用频道(任何有线RPC)

一个 **应用程序** 实例负责处理连接生命周期,并向适当的渠道发送信息.

```js
// api/cable.ts
import {
  Application,
  ConnectionHandle,
  broadcaster,
} from "@anycable/serverless-js";

// Some custom authentication logic
import { verifyToken } from "./auth";

// The identifiers  type describe connection identifiers—e.g., user ID, username, etc.
export type CableIdentifiers = {
  userId: string;
};

// Application instance handles connection lifecycle events
class CableApplication extends Application<CableIdentifiers> {
  // IMPORTANT: When using AnyCable JWT, you don't need to define
  // the connect() callback, authentication doesn't hit your server
  async connect(handle: ConnectionHandle<CableIdentifiers>) {
    const url = handle.env.url;
    const params = new URL(url).searchParams;

    if (params.has("token")) {
      const payload = await verifyToken(params.get("token")!);

      if (payload) {
        const { userId } = payload;

        handle.identifiedBy({ userId });
      }
      return;
    }

    // Reject connection if not authenticated
    handle.reject();
  }

  async disconnect(handle: ConnectionHandle<CableIdentifiers>) {
    // Here you can perform any cleanup work
    console.log(`User ${handle.identifiers!.userId} disconnected`);
  }
}

// Create and instance of the class to use in HTTP handlers (see the next section)
const app = new CableApplication();

// Register channels (see below)

export default app;
```

**频道** 实例反映了特定特性(例如聊天室、通知等)并负责处理收到的命令和订阅生命周期事件:

```js
import { Channel, ChannelHandle } from "@anycable/serverless-js";
// We re-using the identifiers type from the cable application
import type { CableIdentifiers } from "../cable";

// Define the channel params (used by the client according to Action Cable protocol)
type ChatChannelParams = {
  roomId: string;
};

export type ChatMessage = {
  id: string;
  username: string;
  body: string;
  createdAt: string;
};

export default class ChatChannel
  extends Channel<CableIdentifiers, ChatChannelParams, ChatMessage>
{
  // The `subscribed` method is called when the client subscribes to the channel
  // You can use it to authorize the subscription and setup streaming
  async subscribed(
    handle: ChannelHandle<CableIdentifiers>,
    params: ChatChannelParams | null,
  ) {
    if (!params) {
      handle.reject();
      return;
    }

    if (!params.roomId) {
      handle.reject();
      return;
    }

    handle.streamFrom(`room:${params.roomId}`);
  }

  // This method is called by the client
  async sendMessage(
    handle: ChannelHandle<CableIdentifiers>,
    params: ChatChannelParams,
    data: SentMessage,
  ) {
    const { body } = data;

    if (!body) {
      throw new Error("Body is required");
    }

    console.log(
      `User ${handle.identifiers!.username} sent message: ${data.body}`,
    );

    const message: ChatMessage = {
      id: Math.random().toString(36).substr(2, 9),
      username: handle.identifiers!.username,
      body,
      createdAt: new Date().toISOString(),
    };

    // Broadcast the message to all subscribers (see below)
    await broadcastTo(`room:${params.roomId}`, message);
  }
}

// You MUST register a channel instance within the application
// The client MUST use the provided identifier to subscribe to the channel.
app.registerChannel("chat", new ChatChannel());
```

### HTTP 处理器

要用通道粘上HTTP层,我们需要配置HTTP处理器. 下面可以找到一个流行的无服务器平台的例子.

#### 维塞尔

定义 [维塞尔](https://vercel.com/) 无服务器函数如下 :

```js
// api/anycable/connect/route.ts
import { NextResponse } from "next/server";
import { connectHandler, Status } from "@anycable/serverless-js";
import app from "../../cable";

export async function POST(request: Request) {
  try {
    const response = await connectHandler(request, app);
    return NextResponse.json(response, {
      status: 200,
    });
  } catch (e) {
    console.error(e);
    return NextResponse.json({
      status: Status.ERROR,
      error_msg: "Server error",
    });
  }
}

// api/anycable/command/route.ts
import { NextResponse } from "next/server";
import { commandHandler, Status } from "@anycable/serverless-js";
import app from "../../cable";

export async function POST(request: Request) {
  try {
    const response = await commandHandler(request, app);
    return NextResponse.json(response, {
      status: 200,
    });
  } catch (e) {
    console.error(e);
    return NextResponse.json({
      status: Status.ERROR,
      error_msg: "Server error",
    });
  }
}

// api/anycable/disconnect/route.ts
import { NextResponse } from "next/server";
import { disconnectHandler, Status } from "@anycable/serverless-js";
import app from "../../cable";

export async function POST(request: Request) {
  try {
    const response = await disconnectHandler(request, app);
    return NextResponse.json(response, {
      status: 200,
    });
  } catch (e) {
    console.error(e);
    return NextResponse.json({
      status: Status.ERROR,
      error_msg: "Server error",
    });
  }
}
```

您也可以使用通用处理器和一些配置来避免重复:

```js
// next.config.js
const nextConfig = {
  // ...
  rewrites: async () => {
    return [
      {
        source: "/api/anycable/:path*",
        destination: "/api/anycable",
      },
    ];
  },
};

// ...
```

然后可以使用以下处理器:

```js
// api/anycable/route.ts
import { NextResponse } from "next/server";
import { handler, Status } from "@anycable/serverless-js";
import app from "../../cable";

export async function POST(request: Request) {
  try {
    const response = await handler(request, app);
    return NextResponse.json(response, {
      status: 200,
    });
  } catch (e) {
    console.error(e);
    return NextResponse.json({
      status: Status.ERROR,
      error_msg: "Server error",
    });
  }
}
```

## 常见问题

### @anycable/serverless-js 是什么？

无服务器 JS 应用程序的任何有线频道

### 如何安装 @anycable/serverless-js？

在项目目录运行 npm install @anycable/serverless-js，或使用 pnpm add / yarn add / bun add。

### @anycable/serverless-js 支持 TypeScript 吗？

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

### @anycable/serverless-js 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @anycable/serverless-js 需要什么版本的 Node\.js？

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

### @anycable/serverless-js 可以商用吗？

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

### @anycable/serverless-js 的下载量有多少？

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

### @anycable/serverless-js 还在维护吗？

最新版本 0\.2\.3 发布于 2026/08/15（2 个月前）；至今共发布 8 个版本，其中过去 12 个月发布了 2 个；首次发布于 2023/09/22。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

