@anycable/serverless-js

中文文档
0.2.3发布于 2026/08/15MITTypeScriptES Module近 30 天下载 1.2万

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

中文使用文档
文档目录7 节
  1. 结构和组成部分
  2. 使用量
  3. 使用任何有线JWT
  4. 已签名流
  5. 广播
  6. 使用频道(任何有线RPC)
  7. HTTP 处理器

npm version

无线服务器

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

看我们的 演示应用程序 以实例为例.

结构和组成部分

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

软件包也与 HTTP 处理器一起处理 任意有线 RPC- over- HTTP 请求和提供 频道 财务报告和审定财务报表 应用程序 用于描述您的应用程序的实时特性的抽象 .

使用量

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

npm install @anycable/serverless-js

使用任何有线JWT

任何有线JWT 是一种推荐的认证客户的方法。 要启动,您可以使用标识对象并用它生成认证符:

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}`

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

已签名流

您可以创建 签名 实例生成签名的流名,并使用 任何有线酒吧/分店数字 :

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

const streamsSecret = process.env.ANYCABLE_STREAMS_SECRET;

const sign = signer(secret);

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

然后,您可以与客户端使用生成的流名(使用 任何有线JS客户端 SDK:

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
})

广播

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

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 函数以获取它:

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

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

目前,这个软件包只支持通过HTTP进行广播. 然而,AnyCable提供不同的 广播适配器 (如Redis,NATS等),可以融入自己.

使用频道(任何有线RPC)

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

// 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;

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

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处理器. 下面可以找到一个流行的无服务器平台的例子.

维塞尔

定义 维塞尔 无服务器函数如下 :

// 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",
    });
  }
}

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

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

// ...

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

// 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 共发布 8 个版本,首次发布于 2023/09/22;过去 12 个月发布了 2 个版本。

版本发布日期距今
0.2.3latest2026/08/152 个月前
0.2.22026/02/138 个月前
0.2.12024/12/071.9 年前
0.2.02024/04/172 年前
0.1.02023/10/263 年前
0.0.32023/10/253 年前

关于 @anycable/serverless-js 的常见问题

@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 和提交记录判断。