@chainrender/client

中文文档
0.17.0发布于 2026/11/01MITTypeScriptES Module零依赖

ChainRender client SDK — headless, AST-first core: compile, grade, construct, describe, validate, and the machine-readable vocabulary. The foundation the visual builder, MCP server, and AI assistant sit on.

原始使用文档
文档目录11 节
  1. Quickstart
  2. Why slots
  3. Core usage (any framework)
  4. React usage
  5. Built-in slot bindings
  6. First-party on-chain resolver kinds
  7. Checking a tree before you compile it
  8. Safety
  9. Install and networks
  10. Build
  11. Distribution: Farcaster Mini App / standard web app

@chainrender/client

The off-chain hook layer for ChainRender. It does two things:

  1. Render an on-chain component to HTML through a free eth_call (no wallet, no gas).
  2. Bind the component's data-binding slots to live values (balances, ENS names, network, tx status).

It is framework-agnostic and dependency-free at its core (it speaks JSON-RPC directly and hand-rolls the small amount of ABI encode/decode it needs). A React adapter is provided as a separate entry point. This mirrors how Scaffold-ETH wraps wagmi — thin, typed helpers over the thing underneath — except the "thing underneath" is ChainRender's on-chain interpreter.

Quickstart

Install:

npm install @chainrender/client viem

Render an on-chain component to HTML in ~10 lines — no wallet, no gas, just a free eth_call:

import { renderComponent, bindSlots, staticResolvers, makeProviderResolvers } from "@chainrender/client";
import { createPublicClient, http } from "viem";
import { sepolia } from "viem/chains";

const deployment = {
  rpc: "https://ethereum-sepolia-rpc.publicnode.com",
  router: "0x0322b911900cb42694899eb06469c786f52e064c",   // RenderRouter
  registry: "0x36a443515b96b992ee397dfd9a533de72b70c3c9", // ComponentRegistry
};

// 1. render the component (by its content hash) to an escaped HTML string
const html = await renderComponent(deployment, "0x…componentHash");

// 2. mount it in an isolated shadow root
const shadow = document.getElementById("app").attachShadow({ mode: "open" });
shadow.innerHTML = html;

// 3. fill any live data-binding slots (balances, ENS, tx status)
const publicClient = createPublicClient({ chain: sepolia, transport: http(deployment.rpc) });
await bindSlots(shadow, { ...staticResolvers, ...makeProviderResolvers(publicClient) });

That's the whole loop: render on-chain → mount → bind live data. viem is a peer dependency (any compatible provider works); React and Farcaster Mini App adapters are optional entry points (see below). To discover component hashes, index the registry's ComponentRegistered event, or use enumerate(deployment) for a quick proof-of-concept list.

Why slots

ChainRender components are immutable, content-addressed, and stored on-chain, so live data (a balance that changes every block, an ENS name resolved via CCIP-Read) can't be baked into them. Instead the on-chain interpreter emits a slot — an escaped placeholder like:

<span class="cr-slot cr-slot-balance" data-cr-bind="balance" data-cr-arg="0x…">—</span>

The placeholder renders its fallback until this library fills it. ENS and balance bindings are inherently client-side because a contract can't perform the CCIP-Read HTTP that ENS resolution needs; that's the whole reason this off-chain layer exists alongside any on-chain resolver hook.

Core usage (any framework)

import { renderComponent, bindSlots, staticResolvers, makeProviderResolvers } from "@chainrender/client";

const deployment = { rpc: "https://…", router: "0x…", registry: "0x…" };

// 1. render on-chain -> escaped HTML string
const html = await renderComponent(deployment, componentHash);

// 2. mount into an isolated container (shadow root recommended)
const host = document.createElement("div");
const shadow = host.attachShadow({ mode: "open" });
shadow.innerHTML = html;

// 3. fill the slots with live data (pass a viem PublicClient, or any compatible provider)
await bindSlots(shadow, { ...staticResolvers, ...makeProviderResolvers(publicClient) });

enumerate(deployment) lists registered components (proof-of-concept on-chain enumeration; a production app should index the registry's ComponentRegistered event instead).

React usage

import { ChainRenderView, useChainRenderComponent } from "@chainrender/client/react";
import { staticResolvers, makeProviderResolvers } from "@chainrender/client/resolvers";

const resolvers = { ...staticResolvers, ...makeProviderResolvers(publicClient) };

<ChainRenderView deployment={deployment} hash={hash} resolvers={resolvers} styleSheet={themeCss} />

styleSheet accepts the off-chain theme stylesheet you export from the ChainRender Explorer, so the component picks up your colors and type scale. react is an optional peer dependency; the core entry has no framework dependency.

Built-in slot bindings

staticResolvers cover the bindings that need no chain access (address, networkName, avatar placeholder, txStatus fallback). makeProviderResolvers(provider) adds the live ones (balance, ensName, ensNameOrAddress, avatar, networkName) using a viem-compatible provider. Add your own by extending the resolver map — the key is the slot's data-cr-bind kind.

First-party on-chain resolver kinds

Separate from the client-side runtime resolvers above (which fill slots in the browser), some slots bind to an on-chain resolver that serves a kind. ChainRender ships a large first-party set — DeFi, oracle, credentials, ENS, attestations, RWA, reputation, CCIP, messaging, settlement, cross-chain proofs and more — listed in RESOLVER_KINDS and vocabulary().resolverKinds (kind, args, data edge, capability, notes) and exposed per family under kinds, with their KIND_* constants and argument encoders, for example:

  • kinds.oracle — oracle feeds (KIND_FEED, encodeFeedArgs).
  • kinds.credential / kinds.credentialBound — selective-disclosure and bound single-use credentials.
  • kinds.ens — encodeAddrArgs(node), encodeTextArgs(node, key), encodeNameArgs(address), encodeV2Args(resolver, inner, isText) with v2AddrCall / v2TextCall.

Encode a slot's arg exactly as the kind's descriptor says: abi.encode of its args, or the raw bytes when the descriptor has argsEncoding: "packed" (ensName takes exactly the 20 address bytes). The full list is at https://chainrender.org/docs/reference/resolver-kinds.html. Resolver kinds are first-party but extensible — you can deploy your own resolver serving a new kind; this is the set ChainRender ships, not a closed vocabulary.

Checking a tree before you compile it

compile() silently drops anything it doesn't read — an unknown field, an enum value that isn't in the dictionary (role: "note"), a11y fields on an image, args on a batch member. checkNode(tree) reports each with its path and enforces the node/depth/size limits; nodeJsonSchema() is the same rules as a strict JSON Schema for AI tooling.

import { checkNode, nodeJsonSchema } from "@chainrender/client";
const r = checkNode(tree);   // { ok, issues: [{ path, code, message }], nodeCount, depth }

Safety

bindSlots sets textContent, so resolved values are inserted as text and never parsed as HTML. The interpreter's output is already escaped. Render into a shadow root or a sandboxed iframe under a strict Content-Security-Policy rather than a naive innerHTML on a privileged page.

Install and networks

npm install @chainrender/client viem

viem is a peer dependency. The package is chain-agnostic — it hardcodes no addresses, no chainId, and no RPC. You inject a client/RPC and the contract addresses from your deployment, so the same package works on Sepolia, mainnet, or any L2:

import { createPublicClient, http } from "viem";
import { sepolia } from "viem/chains";
const client = createPublicClient({ chain: sepolia, transport: http(RPC_URL) });
// point renders/binds at the addresses from your deployment's addresses.json

Sepolia notes (data, not code): use the Sepolia deployment's addresses; if a component binds a Chainlink feed, use Sepolia feed addresses (or the deployed mock) — a mainnet feed address reverts on Sepolia; and ENS resolves mechanically but Sepolia has far fewer registered names.

Build

npm run build   # tsc -p tsconfig.build.json → self-contained dist/

The build compiles the client together with the chainc/ mirrors into dist/, so the published package has no imports that escape it. prepublishOnly runs it automatically before npm publish.

Distribution: Farcaster Mini App / standard web app

@chainrender/client/miniapp is a thin, fail-closed wrapper that presents a ChainRender app as a Farcaster Mini App and a plain standard web app. The on-chain render is the floor and works standalone; the Mini App layer (embed tags, FID / Sign In With Farcaster, notifications, wallet) is progressive enhancement that no-ops outside a Farcaster host.

import { buildManifest, buildEmbedMetaTags, capabilitiesForEnvelope } from "@chainrender/client/miniapp";
import { mountChainRenderApp, signInWithFarcaster } from "@chainrender/client/miniapp";

// build /.well-known/farcaster.json (add the account association from the Farcaster dev tools)
const manifest = buildManifest({
  name: "My Component", homeUrl: "https://my.app", iconUrl: "https://my.app/icon.png",
  requiredChains: ["eip155:11155111"],                 // Sepolia
  requiredCapabilities: capabilitiesForEnvelope(envelope), // carries the ChainRender capability honesty
});

// in the page: render the on-chain floor, then signal the host
await mountChainRenderApp(async () => { /* inject the eth_call HTML into the DOM */ });

@farcaster/miniapp-sdk is an optional peer dependency, loaded lazily — the adapter builds and runs without it (standard web app mode). See examples/miniapp-wrapper.html for a complete page that is both a web app and a Mini App.

版本与发布记录

@chainrender/client 共发布 16 个版本,首次发布于 2026/09/08;过去 12 个月发布了 16 个版本。

版本发布日期距今
0.17.0latest2026/11/012 天前
0.16.02026/10/304 天前
0.15.02026/10/304 天前
0.14.02026/10/295 天前
0.13.02026/10/286 天前
0.12.02026/10/286 天前

关于 @chainrender/client 的常见问题

@chainrender/client 是什么?

ChainRender客户端SDK -无头,AST-first核心:编译,分级,构建,描述,验证和机器可读词汇表。可视化构建器、MCP服务器和人工智能助手的基础。

如何安装 @chainrender/client?

在项目目录运行 npm install @chainrender/client,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:viem(^2.56.3)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@chainrender/client 支持 TypeScript 吗?

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

@chainrender/client 支持 ESM 还是 CommonJS?

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

@chainrender/client 可以商用吗?

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

@chainrender/client 还在维护吗?

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