@arkiv-network/sdk

中文文档
1.0.1发布于 2026/11/03TypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 7401

用于 Arkiv 块链交互的 TypeScript 客户端库

中文使用文档
文档目录12 节
  1. 安装
  2. 使用量
  3. 先决条件
  4. 项目设置
  5. 定义外观
  6. 创建实体
  7. 查询它
  8. 运行示例
  9. 软件包分发
  10. 运行时间支持
  11. 发展
  12. 微博日志

方块

一个用于 Arkiv 块链交互的 TypeScript 客户端库. Arkiv SDK大力发展 维埃姆 library - 它扩展了Viem的客户端,带有Arkiv的链式特有功能.

viem 是一个 同伴依赖安装在SDK旁边.

安装

npm install @arkiv-network/sdk viem
# or
pnpm install @arkiv-network/sdk viem
# or
bun add @arkiv-network/sdk viem
# or
yarn add @arkiv-network/sdk viem

使用量

下面是帮助您创建使用 Arkiv 查询和写入数据的简单脚本的教程.

先决条件

  • 节点js 22.1.0或更新 (见 节点js.org),或 bun,一个JavaScript/TypeScript运行时间和包管理器,在本地支持TypeScript而无需转接.
  • Arkiv 访问密钥 . Arkiv的公开RPC在防止虐待方面受到很大限制,因此我们建议在 网络/接入密钥。 。 。 .
  • 一些测试网资金. 写一个实体是一种交易,其气体以 tGLM 测试网支付. 从水龙头取来一些你的账户地址 网络/浮标。 。 。 . 项目设置 显示在没有账户的情况下如何创建账户.

项目设置

创建新目录并浏览其中 :

mkdir arkiv-sample
cd arkiv-sample

创建空 example.ts 文件 :

touch example.ts

初始化一个新的 JavaScript/ TypeScript 项目 :

npm init

您可以按下所有默认选项 Enter 在每一个提示. 这一步之后 package.json 将创建类似内容的文件 :

{
  "name": "arkiv-sample",
  "version": "1.0.0",
  "description": "",
  "license": "ISC",
  "author": "",
  "type": "commonjs",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  }
}

修改 "main" 条目为 "example.ts" 设置 "type" 改为 "module" 这么说你 package.json 看起来像这样:

{
  "name": "arkiv-sample",
  "version": "1.0.0",
  "description": "",
  "license": "ISC",
  "author": "",
  "type": "module",
  "main": "example.ts",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  }
}

安装 @arkiv-network/sdk 联合国 viem 使用您首选的软件包管理器对等依赖 :

npm install @arkiv-network/sdk viem

此命令将更新您的 package.json 其中有一节如下:

"dependencies": {
  "@arkiv-network/sdk": "^0.9.0",
  "viem": "^2.38.2"
}

它还将创建一个 node_modules 安装了所有依赖关系的目录.

如果你还没有测试网的账户, 创建一个Viem。 此打印出一个新的私人密钥及其地址 :

node --input-type=module -e "import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; const key = generatePrivateKey(); console.log('Private key:', key); console.log('Address:', privateKeyToAccount(key).address)"

资助地址 水龙头。 。 。 .

最后,创建一个 .env 带有访问密钥和私人密钥的文件。 例子从那里读出来,所以你代码里都没有:

ARKIV_ACCESS_KEY=your-access-key
PRIVATE_KEY=0x-your-private-key

定义外观

Arkiv存储实体,而一个实体是一组被命名,被打入的属性. 你曾经描述过他们 schema,多用 SQL 来描述表格的列,并按列选择节点 索引它。 只有索引列才能被过滤;其余的可以存储和选择,不能 支付指数.

以下是博客文章使用这一计划的例子。 每个例子都表扬在自己的顶端 文件,以便它作为Node.js、Bun或 tsc 类似:

import { addr, bytes, dec, defineSchema, str } from "@arkiv-network/sdk/schema"

// Called with no arguments, a type constructor describes a column.
const Posts = defineSchema("posts", {
  author:    addr().indexed(),
  category:  str().indexed(),
  score:     dec().indexed(),
  title:     str(),                          // stored, not indexed
  body:      bytes(),                        // a blob; bytes can never be indexed
  thumbnail: bytes().optional(),             // any number of bytes columns; this one may be absent
  mimeType:  str().default("text/markdown"), // written on create when left out
})

类型构造器是 bool, (中文(简体) ), i32, (中文(简体) ), u64, (中文(简体) ), u256, (中文(简体) ), dec, (中文(简体) ), str, (中文(简体) ), addr, (中文(简体) ), key 财务报告和审定财务报表 bytes。 。 。 . 每栏可采用下列方法加以改进: .indexed() (每类但 bytes, (中文(简体) ), .optional() 财务报告和审定财务报表 .default(...)。 。 。 .

相同的构造器,使用一个值,生成一个打入的值: dec("4.1") 是一个小数, SQL 方式 已经 DECIMAL 作为类型和 DECIMAL '4.1' 当作一字.

Schema是 SDK 边会:节点只看到属性,每个属性都有类型和索引 旗帜。 计划是您写作和阅读的键盘, 并在运行时检查.

这个名字, "posts",是可选但建议。 一个命名的图案标记它创建的每个实体 已索引 arkiv.schema 属性持有其名称,通过它查询时只匹配实体 用那个标记——一种收藏将一个模型的文档与另一个模型的文档分开的方式. 为了这个 原因 arkiv.schema 无法用作列名.

创建实体

粘贴如下 example.ts。它设置了一个公共客户端,该客户端读取,以及一个钱包客户端,该客户端在交易中签名并发送交易,然后通过计划创建一个帖子:

import { createPublicClient, createWalletClient, ExpirationTime } from "@arkiv-network/sdk"
import { rabdi } from "@arkiv-network/sdk/chains"
import { and, eq, gt } from "@arkiv-network/sdk/query"
import { addr, bytes, dec, defineSchema, str } from "@arkiv-network/sdk/schema"
import { hexToString, http, isHex, stringToBytes } from "viem"
import { privateKeyToAccount } from "viem/accounts"

// The schema from "Define a Schema" above
const Posts = defineSchema("posts", {
  author:    addr().indexed(),
  category:  str().indexed(),
  score:     dec().indexed(),
  title:     str(),
  body:      bytes(),
  thumbnail: bytes().optional(),
  mimeType:  str().default("text/markdown"),
})

// Rabdi is the Arkiv testnet
const chain = rabdi({ accessKey: process.env.ARKIV_ACCESS_KEY ?? "" })

const privateKey = process.env.PRIVATE_KEY
if (!privateKey || !isHex(privateKey)) {
  throw new Error("Set PRIVATE_KEY in .env to the private key of a funded testnet account")
}
const account = privateKeyToAccount(privateKey)

const publicClient = createPublicClient({ chain, transport: http() })
const walletClient = createWalletClient({ chain, transport: http(), account })

// Create an entity. Every required column must be given; a defaulted one (mimeType) left out is
// written with its default. Values carry their type: use the constructors from
// "@arkiv-network/sdk/schema", or a bare string, boolean, number, bigint or Uint8Array where it is
// unambiguous (string -> str, Uint8Array -> bytes, ...). createEntity resolves once the
// transaction is in a block.
const { entityKey, txHash } = await walletClient.createEntity(
  Posts,
  {
    author: addr(account.address),
    category: "docs",
    score: dec("4.5"),
    title: "Hello from Arkiv",
    body: stringToBytes("# Hello\n\nArkiv wishes you all the best!"),
  },
  { expiration: ExpirationTime.fromDays(1) }, // the entity expires in a day
)
console.log("Created entity:", entityKey)
console.log("Transaction hash:", txHash)

// Change one column, leaving the rest alone
await walletClient.patchEntity(Posts, entityKey, { set: { score: dec("4.7") } })

查询它

现在读回帖子。 在结尾添加以下内容: example.ts数字 :

// Get the entity by key, read through the schema
const post = await publicClient.getEntity(entityKey, Posts)
console.log("Title:", post.title.value, "score:", post.score.value)

// Or find it with a query: select what to return, name the schema, then filter
const result = await publicClient
  .select({ $key: true, title: true, score: true, body: true })
  .from(Posts)
  .where(and(eq("category", "docs"), gt("score", dec("4.0"))))
  .ownedBy(account.address)
  .limit(10)
  .fetch()

for (const row of result.entities) {
  console.log(row.$key, row.title.value, row.score.value, hexToString(row.body.value))
}

选择字段 select()

传递无( 或) "*"——通过计划、每个实体领域和每个 栏中——或通过一个对象只获取特定字段。 选择名称实体字段和 属性并列,每个结果都是平行。 实体字段从 $就像他们一样 where数字 : $key, (中文(简体) ), $owner, (中文(简体) ), $creator, (中文(简体) ), $createdAt, (中文(简体) ), $updatedAt, (中文(简体) ), $expiresAt 财务报告和审定财务报表 $creationFlags。任何其他名称都是属性。 属性名称不能从 $,所以请 二从不相撞——一个叫做 owner 刚刚 owner数字 :

// Every entity field and every column
await publicClient.select().from(Posts).where(eq("category", "docs")).fetch();

// Only the fields you need
await publicClient.select({ $key: true, title: true }).from(Posts).where(eq("category", "docs")).fetch();

仅选择所需. 每个选定的字段都会从网络中获取, 所以请求 您不会使用的数据会让查询更慢。 缩小选择范围使响应量小而快.

从您的选择和计划中推断出结果类型: 每个列作为计划键入 声明它,读取您没有选择的字段是一个编译错误 .

const row = (
  await publicClient.select({ $owner: true, score: true }).from(Posts).where(eq("category", "docs")).fetch()
).entities[0]!;
row.$owner;   // ✅ Hex
row.score;    // ✅ DecValue — row.score.value is "4.1"
row.title;    // ❌ compile error — not selected

where 将对照计划检查。 它需要Schema的索引列和系统 属性 $key, (中文(简体) ), $owner, (中文(简体) ), $creator 财务报告和审定财务报表 $expiresAt。在列上过滤时,计划不会 索引,或将一列与另一类型的数值相比较,是一个编译错误:

.where(eq("title", "x"))   // ❌ title is not indexed
.where(eq("score", 5))     // ❌ score is a dec, 5 is an i32 — write dec(5)
.where(between("score", dec(1), 5))  // ❌ both bounds need one type

排序为 orderBy,通过一个键:a asc(...) 或一个 desc(...)调用 orderBy 再来一次 替换命令。 节点将属性排序为一种类型,所以密钥有一种类型: 通过一个计划它是 列,和系统属性 $key, (中文(简体) ), $owner, (中文(简体) ), $creator 财务报告和审定财务报表 $expiresAt 已经修正 这些。 没有计划,写吧。 打电话 orderBy 之后 from(...),因此编译器可以检查 密钥对照方案; 仅在发送查询时检查前给定的密钥 :

import { asc, desc } from "@arkiv-network/sdk/query"

.from(Posts).orderBy(desc("score"))      // score:dec DESC
.from(Posts).orderBy(asc("title"))       // title:str ASC, indexed or not
.from(Posts).orderBy(asc("$expiresAt"))  // $expiresAt:u64 ASC
.where(eq("category", "docs")).orderBy(desc("score", "dec"))  // without a schema
.from(Posts).orderBy(asc("body"))    // ❌ bytes cannot be sorted on
.from(Posts).orderBy(desc("$createdAt"))  // ❌ $createdAt cannot be sorted on
.from(Posts).orderBy(desc("score"), asc("$key"))  // ❌ one key only

任何一栏,但a bytes 一个可以排序,索引或不。 属性未设置或设置为 其它类型,没有值可按每个值排序,并在每个值下排序: asc最后一个 desc。命令贯穿所有匹配,而不是每个页面.

页为 limit 财务报告和审定财务报表 offset。页面最多可容纳100行 offset 跳过之前的匹配 这个 按一个不变的密钥排序, 如 $key,所以页面排行:

const page3 = await publicClient
  .select({ $key: true, title: true })
  .from(Posts)
  .orderBy(asc("$key"))
  .limit(20)
  .offset(40)
  .fetch()

在两个请求之间创建或删除的实体在它之后会转移偏移,所以一行可以重复 或被错过。 要在其他人写的时候准确读取每个匹配, 页面按键: 保留 asc("$key") 排序和过滤器 gt("$key", key(lastKey))时 lastKey 是最后一个 $key 联 合 国 上页。 通过一个计划,通过 { onMismatch: "throw" }: 跳过的实体的一页 没有行,所以没有键可以继续.

一个命名的策略不需要 where 完全没有.. select().from(Posts) 匹配每个文章。 未命名的策略类型 过滤它,所以 where 仅决定哪个实体匹配.

只检查您选择的内容 。 匹配但不符合方案的实体——选定 框,但缺少或持有其他类型,或,对于一个命名的图案,另一个图案 标记 – 放在页面外。 任何人都可以给一个实体写一个查询匹配, 所以一个不 从不辜负别人的阅读 页面可以比其限制少一行,并报告 有多少没有作为 skipped。通过 { onMismatch: "throw" } 无法使用 SchemaMismatchError 相反:

const page = await publicClient.select().from(Posts).where(eq("category", "docs")).fetch();
page.skipped; // matching entities on this page that did not fit Posts

一个查询读取相同,没有计划——比如,探索一个节点持有什么. 别管了 .from(...) 选择意味着它做了什么 "*",下面),各行保留其 形状。 只有检查不见了,还有一个命名的 schema 标记过滤器: 每个属性都会回来 实体拥有的任何价值,或 undefined,以及 where 取出任何属性 :

const row = (
  await publicClient.select({ $key: true, title: true }).where(eq("category", "docs")).fetch()
).entities[0]!;
row.title;    // ArkivValue | undefined — e.g. { type: "str", value: "Hello" }

在不命名的情况下读取每个属性, 请选择 $attributes一张他们所有的地图. "*" (或 无一无一地)在没有计划时与实体字段并取,因为没有栏 以列表形式列出.

$attributeSchema 用于找出实体持有哪些东西而不获取其价值: 属性的名称、类型以及是否索引。 价值可以很大——a bytes 属性 超过128KiB, RPC的端点可能会限制它发出的响应,所以100的一页 具有每个属性的实体可能比它返回时还要多。 首先获取计划, 然后选择 名称所需的属性。 它从来没有参与 "*"; 按名称选择它 :

const page = await publicClient.select({ $key: true, $attributeSchema: true }).where(eq("category", "docs")).fetch();
page.entities[0]?.$attributeSchema; // { title: { type: "str", indexed: false }, body: { type: "bytes", indexed: false } }

两者都通过一个计划.

脚枪 : 通过选择的内线。 存储在变量中的选择会拓宽其 true 数值 改为 boolean,因此只有运行时才知道哪些字段返回,结果的每个字段都是 选项。 如果你需要重用,请注明 as const数字 :

const fields = { $owner: true, title: true } as const;
await publicClient.select(fields).from(Posts).where(eq("category", "docs")).fetch();

运行示例

您有多个选项可以运行您的 TypeScript 样本 。 每个装入你的 .env 文件 :

  • 带有Node.js(使用实验类型Script支持):

    node --env-file=.env --experimental-strip-types example.ts
    
  • 带有 Bun( 本地类型脚本支持, 负载) .env 单枪匹马:

    bun example.ts
    
  • 经典节点.js(使用转录到JavaScript):

    1. 如果您还没有安装类型脚本和节点.js类型定义 :
      npm install typescript @types/node
      
    2. 以默认设置初始化类型脚本配置 :
      npx tsc --init
      
      这将创建一个 tsconfig.json 文档。 设定 "types": ["node"] 在其中,这样 process.env 类型检查.
    3. 翻译你的 .ts 文件输入 .js数字 :
      npx tsc --outDir dist
      
      这创造了一个 dist 包含 example.js (被转接的代码),连同相应的类型声明和源地图文件.
    4. 运行转写脚本 :
      node --env-file=.env dist/example.js
      

样本代码也可以在 sample 此仓库的目录 .

软件包分发

此软件包支持多个模块格式实现最大兼容性 :

  • ES 模块 (单位:千美元)dist/*.js- 对于现代 import 声明
  • 常见JS (单位:千美元)dist/*.cjs- 为节点.js require()
  • 类型声明 (单位:千美元)dist/*.d.ts 财务报告和审定财务报表 dist/*.d.cts) - 完整类型脚本支持

建筑用途 s 生成具有适当类型声明的无害环境管理格式和共同JS格式.

运行时间支持

节点.js(ESM):

import { createPublicClient } from '@arkiv-network/sdk';  // Uses compiled ESM

节点.js(CommonJS):

const { createPublicClient } = require('@arkiv-network/sdk');  // Uses compiled CJS

Bun( TypeScript 本地语) :

import { createPublicClient } from '@arkiv-network/sdk'; // Uses *.ts directly

所有格式在使用TypeScript时都提供全类型安全性和IntelliSense支持.

发展

要安装依赖性 :

bun install

构建所有产出(ESM、CommonJS和类型声明):

bun run build

有关构建SDK的更多信息,请参见: 贝鲁特,md

要运行类型检查 :

bun run type-check

给 :

bun run lint

欲了解更多信息,请查阅: 捐款额

微博日志

设定 DEBUG 环境变量(或在浏览器中 DEBUG 键入 localStorage查看动词日志:

DEBUG=arkiv:* bun run your-script

调整命名空间(例如, arkiv:query:* 或者说 arkiv:actions:wallet:*以特定日志源为目标,前缀1 - 将它排除在外。 未设置 DEBUG 关闭调试输出.

版本与发布记录

@arkiv-network/sdk 共发布 100 个版本,首次发布于 2025/10/20;过去 12 个月发布了 76 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.0.1latest2026/11/034 天前
1.0.0-dev.2dev2026/11/035 天前
1.0.02026/10/308 天前
1.0.0-dev.12026/10/308 天前
0.9.0-next.5next2026/10/308 天前
0.9.0-next.32026/10/299 天前

其他发布通道:advanced → 0.8.0-advanced.3,next → 0.9.0-next.5,dev → 1.0.0-dev.2。

关于 @arkiv-network/sdk 的常见问题

@arkiv-network/sdk 是什么?

用于 Arkiv 块链交互的 TypeScript 客户端库

如何安装 @arkiv-network/sdk?

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

@arkiv-network/sdk 支持 TypeScript 吗?

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

@arkiv-network/sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@arkiv-network/sdk 需要什么版本的 Node.js?

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

@arkiv-network/sdk 可以商用吗?

@arkiv-network/sdk 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@arkiv-network/sdk 的下载量有多少?

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

@arkiv-network/sdk 还在维护吗?

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