mcpField
W
walrus-ts-sdk

walrus-ts-sdk

github.com/mystenlabs開発344 回インストール1 週間前に更新
リポジトリ

walrus-ts-sdk について

walrus-ts-sdkは、公式の`@mysten/walrus` TypeScript SDKでWalrusのBlobやファイルを読み書きするためのスキルです。ストレージノードへの直接アクセス、アップロードリレー、再開可能な段階的書き込みを扱います。

主な機能

  1. 01Blobとファイルの読み書き
  2. 02Quilt内のファイル処理
  3. 03アップロードリレーによるブラウザー送信
  4. 04中断した書き込みフローの再開
  5. 05SuiおよびWalrusクライアントの設定
  6. 06利用前のBlob可用性確認

活用シーン

  1. 01TypeScriptアプリへのWalrusストレージ導入
  2. 02ブラウザーウォレットでのアップロード
  3. 03中断したBlobアップロードの再開
  4. 04保存データに依存する前の認証状態確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mystenlabs/walrus-skills --skill walrus-ts-sdk

インストール後、Claude Code で/walrus-ts-sdkを入力して読み込まれたか確認します。

同梱ファイルevals/evals.json

詳細

Walrus TypeScript SDK

ソースの制約: このスキルの情報は、 Walrus TypeScript SDK のドキュメント、 公式サンプル、 およびWalrus のドキュメントからのみ取得しています。 このスキルを拡張する場合は、これらのソースのみを参照してください。

@mysten/walrus パッケージは、Mysten Labs が保守する Walrus の公式 TypeScript SDK です。Walrus のストレージノードに直接接続するか、アップロードリレー経由で動作します。リレーを使わない場合、ブロブの書き込みには約 2,200 件、読み込みには約 335 件のリクエストが必要です。そのため、多くのアプリケーションでは、SDK のドキュメントはパブリッシャーとアグリゲーターの利用を推奨しています。この SDK は、Walrus と直接やり取りする必要があるアプリケーションや、ユーザーが自分でストレージ料金を支払うアプリケーション向けです。

Walrus に保存されるすべてのブロブは公開されています。機密情報を保存する場合は、保存前にクライアント側で暗号化してください(walrus-data-security を参照)。

このスキルのすべてのパターンは、以下を参考にしています。

SDK API に不明な点がある場合は、回答する前に該当するページを取得してください。メソッドの一覧は、WalrusClient TypeDocsで確認できます。


関連スキル

トピックスキル読み込むタイミング
CLI 操作walrus-cliSDK ではなく walrus バイナリを使う場合
HTTP APIwalrus-http-api任意の言語から REST エンドポイントを使う場合
機密性walrus-data-securityアップロード前にブロブを暗号化する場合
ブロブ管理walrus-blob-lifecycleブロブの延長、削除、共有、または可用性の検証を行う場合
Quiltswalrus-quilts多数の小さなブロブを 1 つの単位にまとめる場合
Move 連携walrus-move-integrationWalrus ブロブを Move コントラクトでラップする場合

スキルの内容

主な概念
  • クライアントのセットアップ。 Sui クライアントを作成し、Walrus 拡張機能で拡張します:new SuiGrpcClient({ network, baseUrl }).$extend(walrus())。拡張機能には client.walrus からアクセスします。新しいコードでは、非推奨の JSON-RPC SuiClient を使用しないでください。
  • 2 つの API レベル。 WalrusFile API(getFiles、writeFiles)は、通常のブロブおよび Quilts として保存されたデータを扱うもので、推奨されるエントリーポイントです。低レベルの readBlob / writeBlob API は、単一の Uint8Array ブロブを扱います。
  • 処理フロー。 writeFilesFlow と writeBlobFlow は、書き込みを encode、register、upload、certify の各ステップに分割します。ブラウザーウォレット(署名ごとにユーザー操作が必要)や、クラッシュから復旧可能なアップロード(run() は保存可能なステップを返し、それを resume として渡して再開)には、これらを使用してください。
  • 署名者。 書き込みには、登録と認証のトランザクション用の SUI と、ストレージ料金および書き込み手数料用の WAL を保有するアドレスの Signer が必要です。読み込みには署名者は必要ありません。
  • アップロードリレー。 ブラウザーやモバイルのクライアントでは、すべてのシャードに到達するのに十分な数の接続を開けません。uploadRelay オプションを使うと、ブロブをリレーに送信してスライスを配布できます。クライアントは引き続き Sui 上で署名し、支払いを行います。リレーによってはチップが必要です。
  • ブロブ ID とオブジェクト ID。 blobId(URL セーフな base64。コンテンツから導出されます)は読み込みに使用します。blobObject.id(0x...)は、ライフサイクル操作および可用性の検証に使う Sui オブジェクトです。
  • コミュニティ SDK。 TypeScript 以外の言語向けには、Go、PHP、Python のコミュニティ SDK があります。これらは HTTP 経由でアグリゲーターやパブリッシャーと通信します。
インストールとセットアップ
npm install --save @mysten/walrus @mysten/sui
import { SuiGrpcClient } from '@mysten/sui/grpc';
import { walrus } from '@mysten/walrus';

const client = new SuiGrpcClient({
  network: 'testnet',
  baseUrl: 'https://fullnode.testnet.sui.io:443',
}).$extend(walrus());

SDK には、各ネットワークのパッケージ ID とオブジェクト ID が含まれています。別のデプロイ先を指定するには、walrus({...}) に packageConfig: { systemObjectId, stakingPoolId } を渡します。ストレージノードへのリクエスト(タイムアウト、再試行、ログ記録)をカスタマイズするには、storageNodeClientOptions: { fetch, timeout, onError } を渡します。

WalrusFile API を使った読み取り

getFiles は blob ID と quilt ID を受け取り、WalrusFile オブジェクトを返します。クライアントが 1 つの quilt から複数のファイルを効率よく読み込めるよう、バッチで読み取ります。

const [file1, file2] = await client.walrus.getFiles({ ids: [anyBlobId, orQuiltId] });

const bytes = await file1.bytes();   // Uint8Array
const text = await file1.text();     // utf-8 string
const json = await file2.json();     // parsed JSON

// Files stored in a quilt also carry an identifier and tags
const identifier: string | null = await file1.getIdentifier();
const tags: Record<string, string> = await file1.getTags();

blob ID を使って WalrusBlob を取得し、quilt の場合は識別子、タグ、または quilt ID でファイルを一覧表示することもできます。

const blob = await client.walrus.getBlob({ blobId });
const files = await blob.files();
const [readme] = await blob.files({ identifiers: ['README.md'] });
const textFiles = await blob.files({ tags: [{ 'content-type': 'text/plain' }] });
WalrusFile API を使った書き込み

Uint8Array、Blob、または文字列からファイルを作成して書き込みます。1 回の writeFiles 呼び出しで書き込むファイルはすべて 1 つの quilt に格納されます。そのため、可能であれば複数のファイルをまとめて書き込みます。quilt のエンコードは、ファイルが 1 つだけの場合は効率が低くなります。

import { WalrusFile } from '@mysten/walrus';

const file1 = WalrusFile.from({ contents: new Uint8Array([1, 2, 3]), identifier: 'file1.bin' });
const file2 = WalrusFile.from({
  contents: new TextEncoder().encode('Hello from the TS SDK!!!\n'),
  identifier: 'README.md',
  tags: { 'content-type': 'text/plain' },
});

const results = await client.walrus.writeFiles({
  files: [file1, file2],
  epochs: 3,
  deletable: true,
  signer: keypair,
});
// results: { id, blobId, blobObject }[]
生の blob:readBlob と writeBlob
const data = await client.walrus.readBlob({ blobId }); // Uint8Array

const { blobId } = await client.walrus.writeBlob({
  blob: new TextEncoder().encode('Hello from the TS SDK!!!\n'),
  deletable: false,
  epochs: 3,
  signer: keypair,
});

writeBlob と writeFiles は、クラッシュから復旧できるアップロードのために onStep と resume を受け付けます。onStep から各ステップを保存し、クラッシュ後に続行するには、保存したステップを resume として渡します。

フロー:ブラウザーウォレットと再開可能なアップロード

ブラウザーウォレットは署名のためにポップアップを開きます。ユーザー操作への直接の応答として開かれなかったポップアップは、ブロックされることがあります。writeFilesFlow は書き込みを分割するため、登録トランザクションと認証トランザクションをそれぞれ別のボタンから署名できます。

const flow = client.walrus.writeFilesFlow({
  files: [WalrusFile.from({ contents: new Uint8Array(fileData), identifier: 'my-file.txt' })],
});
await flow.encode();

// Button 1
async function handleRegister() {
  const registerTx = flow.register({ epochs: 3, owner: currentAccount.address, deletable: true });
  const result = await signAndExecuteTransaction({ transaction: registerTx });
  if (result.$kind === 'FailedTransaction') {
    throw new Error(`Registration failed: ${result.FailedTransaction.status.error?.message}`);
  }
  await flow.upload({ digest: result.Transaction.digest });
}

// Button 2
async function handleCertify() {
  const certifyTx = flow.certify();
  const result = await signAndExecuteTransaction({ transaction: certifyTx });
  if (result.$kind === 'FailedTransaction') {
    throw new Error(`Certification failed: ${result.FailedTransaction.status.error?.message}`);
  }
  const files = await flow.listFiles();
}

個別の操作を行わずに実行する場合は、パイプライン全体を非同期イテレーターとして実行し、各ステップを保存します。

const flow = client.walrus.writeBlobFlow({ blob });
for await (const step of flow.run({ signer, epochs: 3, deletable: true })) {
  await db.save(fileId, step); // a WriteBlobStep, persisted for crash recovery
}

// Resume: completed steps are skipped and only missing slivers are uploaded
const resumed = client.walrus.writeBlobFlow({ blob, resume: await db.load(fileId) });

executeRegister({ signer, epochs, deletable, owner }) と executeCertify({ signer }) は、署名を代行し、型付きのステップ結果を返します。

ブラウザーアプリ向けアップロードリレー
const client = new SuiGrpcClient({
  network: 'testnet',
  baseUrl: 'https://fullnode.testnet.sui.io:443',
}).$extend(
  walrus({
    uploadRelay: {
      host: 'https://upload-relay.testnet.walrus.space',
      sendTip: { max: 1_000 }, // maximum tip in MIST; the client reads the required tip itself
    },
  }),
);
  • host は必須です。Mainnet:https://upload-relay.mainnet.walrus.space。Testnet:https://upload-relay.testnet.walrus.space。
  • リレーは <host>/v1/tip-config でチップの設定を公開します。チップは const(blob ごとに固定)または linear(base と perEncodedKib)です。sendTip: { max } を指定すると、クライアントは最大額まで支払います。チップを手動で設定するには、sendTip: { address, kind: { const: 105 } } または kind: { linear: { base: 105, perEncodedKib: 10 } } を渡します。
  • 必要なチップが max を超えると、アップロードは Tip amount exceeds the maximum allowed tip というエラーで失敗します。max を引き上げてください。
blob に依存する前に検証する

書き込みの結果だけでは、blob が永続的に保存されている証拠にはなりません。Blob オブジェクトを読み戻し、認証済みで、ストレージ期間内にあり、削除可能ではないことを確認します。

const blob = await walrusClient.getBlobObject(blobObjectId); // blobObject.id from the write result
const durable =
  blob.certified_epoch != null &&          // null until certified
  currentEpoch < blob.storage.end_epoch && // read the epoch from system state or `walrus info`
  !blob.deletable;
if (!durable) throw new Error('Blob is not durably available yet; do not depend on it');

Sui オブジェクトの blob_id フィールドは u256 であり、アグリゲーターの URL で使われる base64 blob ID ではありません。このフィールドを URL に直接組み込まず、オブジェクト ID で読み取ってください。可用性と整合性の完全な確認方法については、walrus-blob-lifecycle を参照してください。

エラー処理

エポックの切り替わり前後に古いキャッシュデータから発生するエラーは、RetryableWalrusClientError を拡張します。クライアントをリセットして再試行してください。

import { RetryableWalrusClientError } from '@mysten/walrus';

if (error instanceof RetryableWalrusClientError) {
  client.walrus.reset();
  // retry the operation
}

readBlob などの高レベルメソッドは、これらのケースをすでに再試行し、一部のノードが失敗しても処理を続行します。SDK が吸収するストレージノード個別のエラーを確認するには、storageNodeClientOptions: { onError: (error) => console.log(error) } を渡します。

WASM の読み込み:Vite と Next.js

SDK では blob のエンコードとデコードに WASM バインディングが必要です。Node.js、Bun、および一部のバンドラーでは設定は不要です。バンドラーがバイナリを見つけられない場合は、クライアントにその場所を指定します。

// Vite
import walrusWasmUrl from '@mysten/walrus-wasm/web/walrus_wasm_bg.wasm?url';

const client = new SuiGrpcClient({ network: 'testnet', baseUrl: 'https://fullnode.testnet.sui.io:443' })
  .$extend(walrus({ wasmUrl: walrusWasmUrl }));

// Or load from a CDN / self-host
walrus({ wasmUrl: 'https://unpkg.com/@mysten/walrus-wasm@latest/web/walrus_wasm_bg.wasm' });
// Next.js API routes (webpack and Turbopack alike)
const nextConfig: NextConfig = {
  serverExternalPackages: ['@mysten/walrus', '@mysten/walrus-wasm'],
};

serverExternalPackages を指定せずに WASM ローダーをサーバールートにバンドルすると、バイナリの場所を特定できなくなることがあります。Turbopack では、これが /ROOT/... のような仮想化されたパスとして現れます。これを使用できない場合は、Vite の例と同様に wasmUrl でウェブビルドを指定してください。

既知のフェッチに関する制限
  • Node.js のデフォルトの connectTimeout は 10 秒ですが、応答が遅いノードもあります。storageNodeClientOptions でカスタムの fetch(例:undici の Agent({ connectTimeout }))を使って、タイムアウトを延長してください。
  • Bun では、abort シグナルを送るとリクエストは応答しなくなりますが、拒否される前にプロミスが完了まで待機し続けます。
ルール
  1. SuiGrpcClient を拡張します。 new SuiGrpcClient({ network, baseUrl }).$extend(walrus()) を使ってください。JSON-RPC クライアントは非推奨です。
  2. SDK にあるメソッド名を使います。 ファイルとキルトには getFiles / writeFiles、生の BLOB には readBlob / writeBlob、手順に沿った書き込みには writeFilesFlow / writeBlobFlow を使ってください。storeBlob はありません。
  3. 書き込みには必ず epochs、deletable、signer を渡します。 signer には、ガス用の SUI と、ストレージおよび書き込み手数料用の WAL が必要です。
  4. ブラウザーではアップロードリレーを使います。 uploadRelay.host を設定し、リレーの /v1/tip-config に対応できる十分な値を sendTip.max に設定してください。
  5. BLOB に依存する前に検証します。 Blob オブジェクトの certified_epoch、storage.end_epoch、deletable を確認してください。
  6. RetryableWalrusClientError が発生したらリセットします。 client.walrus.reset() を呼び出して再試行してください。成功が保証されるわけではありませんが、エポック変更後に古くなる状態をクリアできます。
  7. 機密データはアップロード前に暗号化します。 Walrus の BLOB はすべて公開されています。
よくある間違い
  • storeBlob を呼び出す。 このメソッドはありません。writeBlob(生のバイト列)または writeFiles(ファイル。キルトとして保存されます)を使ってください。
  • 生の文字列やオブジェクトを BLOB として渡す。 writeBlob が受け取るのは Uint8Array です。WalrusFile.from が受け取るのは Uint8Array、Blob、または文字列です。JSON は new TextEncoder().encode(JSON.stringify(obj)) で変換してください。
  • Vite で optimizeDeps.exclude を使う。 ドキュメントに記載されている修正方法は、@mysten/walrus-wasm/web/walrus_wasm_bg.wasm の ?url インポートと wasmUrl オプションを使う方法です。Next.js のルートでは serverExternalPackages を使ってください。
  • ブラウザーで、1 回のクリックから register と certify の署名を行う。 2 回目のポップアップはブロックされます。トランザクションごとにユーザー操作が 1 回必要となるように、writeFilesFlow を使ってください。
  • writeFiles で単一ファイルを多数書き込む。 呼び出しごとに 1 つのキルトが作成されます。ファイルをまとめて 1 回の呼び出しで渡してください。
  • 書き込み結果を耐久性の証明として扱う。 登録済みの BLOB は認証済みとは限りません。getBlobObject で Blob オブジェクトを読み戻し、certified_epoch を確認してください。
  • Tip amount exceeds the maximum allowed tip。 sendTip.max を引き上げ、リレーの /v1/tip-config を確認してください。
  • reset() せずに再試行する。 エポック変更後はクライアントにキャッシュされた委員会情報が古くなっています。RetryableWalrusClientError が発生した場合は、再試行する前にリセットしてください。
  • システムオブジェクト ID をハードコードする。 SDK にはネットワークごとの ID が含まれています。packageConfig はカスタムデプロイの場合にのみ使ってください。

コメント