@cratestack/link-batch

中文文档
0.19.3发布于 2026/11/09MITTypeScriptES Module构建来源已验证近 30 天下载 2632

A batshit-style automatic batch scheduler for CrateStack's generated TypeScript RPC client, shipped as an RpcLink.

原始使用文档
文档目录3 节
  1. Usage
  2. Batching semantics
  3. Known limitations

@cratestack/link-batch

A batshit-style automatic batch scheduler for CrateStack's generated TypeScript RPC client (transport rpc schemas), shipped as an RpcLink (issue #182) rather than a fetch override — so it composes with @cratestack/link-logger, a retry link, or an auth-refresh link instead of clobbering them.

React Native compatibility evidence is tracked in docs/react-native-compatibility.md.

Multiple unary calls issued in the same tick collapse into a single POST /rpc/batch request instead of firing one POST /rpc/{op_id} each.

Usage

import { createBatchLink } from "@cratestack/link-batch";
import { CratestackRpcRuntime } from "./generated/runtime"; // your project's generated client

const runtime = new CratestackRpcRuntime("https://api.example.com", {
  links: [createBatchLink()],
});
const client = new MyGeneratedClient(runtime);

// These three calls, if issued in the same tick, become ONE /rpc/batch request:
const [a, b, c] = await Promise.all([
  client.widgets.get(1),
  client.widgets.get(2),
  client.widgets.get(3),
]);

Batching semantics

  • Window: defaults to queueMicrotask — calls fired synchronously in the same tick (e.g. inside Promise.all) collapse. Pass windowMs to widen the window across ticks.
  • Partitioning (fixed in #273; versions before this carried a bug here — see "Known limitations" below): each flush is split into partitions by transport envelope — headers (excluding Idempotency-Key, which is carried per-frame, not per-request), fetch reference, codec reference, and the resolved batch URL — and every partition is sent as its own POST /rpc/batch. Calls that share an envelope, the overwhelmingly common case, still collapse into exactly one request; calls that don't (e.g. two different Authorization headers) each keep their own, in a separate request, rather than one silently overwriting the other's.
  • Aggregate headers: pass headers to createBatchLink({ headers }) to declare headers that every synthesized /rpc/batch request carries, merged over each partition's own — a same-named per-call header is overridden by this value, not the other way around. Use this for service-level headers (e.g. an API key) rather than per-tenant auth, which should come from per-call headers that drive partitioning.
  • maxBatchSize is enforced per partition, not globally across the flush — a single oversized partition chunks into several concurrent requests; it never borrows headroom from a different partition.
  • Dedup: only calls sharing an explicit idempotencyKey are collapsed into one request frame by default — that's already the caller's own signal that the call is a safe repeat. Calls with no idempotency key are never auto-collapsed, since the server does no dedup of its own and silently merging two textually-identical but unmarked mutations would be unsafe. Pass a custom dedupe for full value-based collapsing, or () => null to disable dedup and only batch. Dedup runs within a partition — it never collapses calls across two different envelopes.
  • Correlation: results are fanned back out by matching each response frame's id, not array position — the server's /rpc/batch contract already guarantees order (see docs/design/rpc-transport.md §3.2), but id-based matching is strictly more robust and mirrors the repo's own Rust client-side batch debouncer (examples/rpc-batch-debounce).
  • Failure isolation: a partition that fails (network error, non-OK response) only rejects the callers queued in that partition — it never affects a concurrently in-flight partition.

Known limitations

  • Aborting an individual call's AbortSignal only cancels it if its batch hasn't been sent yet — it does not cancel an in-flight /rpc/batch request.
  • (Fixed in #273, kept here for anyone reading an older version's docs) Before #273, the synthesized /rpc/batch request reused the first queued call's headers/fetchFn/codec for the whole flush — per-call custom headers on later calls in the same window were silently dropped from the aggregate request instead of applied. This is why partitioning exists now.

版本与发布记录

@cratestack/link-batch 共发布 67 个版本,首次发布于 2026/08/02;过去 12 个月发布了 67 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.19.3latest2026/11/091 天前
0.19.22026/11/091 天前
0.19.12026/11/092 天前
0.19.02026/11/092 天前
0.18.12026/11/073 天前
0.18.02026/11/074 天前

关于 @cratestack/link-batch 的常见问题

@cratestack/link-batch 是什么?

A batshit-style automatic batch scheduler for CrateStack's generated TypeScript RPC client, shipped as an RpcLink.

如何安装 @cratestack/link-batch?

在项目目录运行 npm install @cratestack/link-batch,或使用 pnpm add / yarn add / bun add。

@cratestack/link-batch 支持 TypeScript 吗?

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

@cratestack/link-batch 支持 ESM 还是 CommonJS?

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

@cratestack/link-batch 需要什么版本的 Node.js?

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

@cratestack/link-batch 可以商用吗?

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

@cratestack/link-batch 的下载量有多少?

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

@cratestack/link-batch 还在维护吗?

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