@cratestack/cbor

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

Umbrella CBOR codec for CrateStack's generated TypeScript RPC clients: conditional exports auto-select @cratestack/cbor-node in Node and @cratestack/cbor-web in the browser behind one import path, one uniform async createCborCodec() API on both platforms.

原始使用文档
文档目录8 节
  1. How auto-selection works
  2. Escape hatch: explicit subpaths
  3. Sync vs. async: one uniform API
  4. Error handling
  5. Null handling
  6. Contributing to this package (monorepo-local dev)
  7. See Also
  8. License

@cratestack/cbor

A thin umbrella package that auto-selects the right CBOR backend for CrateStack's generated TypeScript RPC clients: @cratestack/cbor-node (#286, native N-API) in Node, @cratestack/cbor-web (#287, WASM) in the browser — one npm install, one import path, the environment picks the implementation. The final piece of epic #285.

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

npm install @cratestack/cbor
import { createCborCodec } from "@cratestack/cbor";

const codec = await createCborCodec();

const bytes = codec.encode({ hello: "world" });
const value = codec.decode(bytes);

Node projects never download the WASM binary; browser bundles never pull in native .node files — each platform's dependencies (@cratestack/cbor-node or @cratestack/cbor-web) is only actually loaded once the matching exports condition resolves.

How auto-selection works

This package's package.json declares conditional exports for its "." entry:

{
  "exports": {
    ".": {
      "node": { "types": "./dist/node.d.ts", "import": "./dist/node.js" },
      "browser": { "types": "./dist/web.d.ts", "import": "./dist/web.js" },
      "default": { "types": "./dist/web.d.ts", "import": "./dist/web.js" }
    }
  }
}
  • Node's own module resolver (and any bundler/test runner that sets the "node" condition — e.g. Vitest's default environment: "node", webpack's target: "node") picks dist/node.js, which re-exports @cratestack/cbor-node.
  • A browser-targeting bundler (Vite's client build, webpack's default web target, Next.js client bundles) sets the "browser" condition and picks dist/web.js, which re-exports @cratestack/cbor-web.
  • "default" is the fallback for resolvers that set neither condition — it points at the WASM build (dist/web.js), the more broadly portable of the two: it only needs fetch/URL/WebAssembly, all present in every modern JS runtime (Node, browsers, edge/worker runtimes), whereas the Node build depends on a native .node binary that plainly cannot load outside Node. The same reasoning is why the package-level "main"/"types" fields (read by tooling that ignores exports entirely) also point at the WASM build.

Escape hatch: explicit subpaths

Conditional exports resolution isn't perfectly consistent across every bundler/SSR setup — some SSR frameworks resolve the "node" condition even for a module that will also ship to the client (their SSR build sets "node" because the code runs under Node during the server render, even though the same module graph gets bundled for the browser too). When automatic resolution doesn't do what you need, import the platform build directly:

// Force the native Node build, regardless of which condition the
// resolver would otherwise pick:
import { createCborCodec } from "@cratestack/cbor/node";

// Force the WASM build — e.g. from an SSR entry point whose bundler
// resolves "node" but whose output actually needs to run in the browser:
import { createCborCodec } from "@cratestack/cbor/web";

Both subpaths export the exact same createCborCodec() shape as the root entry point — they're what the root entry point's "node"/"browser" conditions point at internally, just addressable directly.

Sync vs. async: one uniform API

@cratestack/cbor-node's own export (cborCodec) is a plain synchronous object — native N-API modules load synchronously via Node's require/ESM interop, so there's no async step to wait on. @cratestack/cbor-web's own export is necessarily async (createCborCodec(): Promise<CratestackRpcCodec>) — one-time WASM instantiation has no synchronous equivalent in a browser.

This package normalizes both platforms to the same async-factory shape: createCborCodec() everywhere, always returning a Promise. On Node that Promise resolves immediately (the underlying codec is already loaded and synchronous by the time the module's import completes) — it's strictly unnecessary async ceremony for that platform alone, but it buys a single, genuinely platform-agnostic call site. await createCborCodec() behaves identically no matter which condition resolved; nothing in consuming code needs to branch on environment. Once resolved, every encode/decode call is synchronous on both platforms — the async cost, real or nominal, is paid exactly once.

The alternative — exposing the platform difference directly (a sync export on Node, an async factory in the browser) and documenting it — was considered and rejected: it would force every consumer of this umbrella package to either branch on environment or always await a value that's sometimes a real async boundary and sometimes not, which defeats the purpose of an umbrella package that's supposed to hide exactly that kind of platform difference.

Error handling

Malformed CBOR input on decode, or a value encode can't represent, throws a catchable JS Error on both platforms — see @cratestack/cbor-node's and @cratestack/cbor-web's own READMEs for the platform-specific mechanism (native panic-to-exception conversion vs. a non-poisoning WASM trap boundary).

Null handling

Both backends translate every JSON null (top-level or nested) to the real CBOR null byte (0xf6), matching cratestack-codec-cbor's own Option::None encoding — not the empty-array quirk (0x80) some CBOR backends produce for a bare unit type. See either platform package's README for detail.

Contributing to this package (monorepo-local dev)

This package's own build (tsc) is pure TypeScript — it never needs a Rust or wasm toolchain. But its dependencies are @cratestack/cbor-node and @cratestack/cbor-web, which do. Within this monorepo, this package's turbo build task deliberately does not build those two siblings automatically (see turbo.json's @cratestack/cbor#build override) — a default dependency edge would force every toolchain-free environment (including this repo's own js CI job) to compile native/wasm code just to typecheck a thin re-export wrapper.

Practical effect: pnpm turbo run build test lint --filter='./packages/cratestack-cbor' type-checks cleanly and passes lint anywhere, but its Node round-trip tests (tests/node.test.ts) only run for real if @cratestack/cbor-node is already built — otherwise they skip (not fail) with a console warning. For real coverage while developing, build the sibling first:

pnpm turbo run build --filter='./packages/cratestack-cbor-node'
pnpm turbo run build test lint --filter='./packages/cratestack-cbor'

Or just run the full unfiltered pnpm turbo run build test lint at the repo root — that builds every package as its own top-level target regardless of this edge, so the siblings are present and the tests run for real.

See Also

  • @cratestack/cbor-node — the Node/native implementation (napi-rs). Its README lists the prebuilt platforms; glibc and musl (Alpine) Linux x64/arm64 are both covered since cratestack#850, so createCborCodec() under the "node" condition no longer fails to initialize on an Alpine base image. win32-arm64 remains uncovered.
  • @cratestack/cbor-web — the browser/WASM implementation (wasm-bindgen).
  • crates/cratestack-codec-cbor — the underlying, unchanged Rust codec both implementations wrap.

License

MIT

版本与发布记录

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

版本发布日期距今
0.19.3latest2026/11/101 天前
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/cbor 的常见问题

@cratestack/cbor 是什么?

Umbrella CBOR codec for CrateStack's generated TypeScript RPC clients: conditional exports auto-select @cratestack/cbor-node in Node and @cratestack/cbor-web in the browser behind one import path, one uniform async createCborCodec() API on both platforms.

如何安装 @cratestack/cbor?

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

@cratestack/cbor 支持 TypeScript 吗?

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

@cratestack/cbor 支持 ESM 还是 CommonJS?

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

@cratestack/cbor 需要什么版本的 Node.js?

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

@cratestack/cbor 可以商用吗?

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

@cratestack/cbor 的下载量有多少?

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

@cratestack/cbor 还在维护吗?

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