# TypeScript SDK

> @nodaro/sdk をインストールし、API トークンで認証して、Node.js、ブラウザー、エッジランタイムの TypeScript から、Nodaro のノードとワークフローを実行します。

Source: https://nodaro.ai/ja/docs/developers/sdk

**Nodaro TypeScript SDK** は、Nodaro REST API の型付きクライアントで、npm に `@nodaro/sdk` として公開されています。単体のノードとワークフロー全体を実行してその結果を待ち、キャラクター、ボイス、メディアなどを管理します。Node.js、ブラウザー、エッジランタイムで動作し、API のすべてのエラーは、キャッチできる型付きのエラークラスとして届きます。

## インストール
```bash
npm install @nodaro/sdk
```

- このパッケージは、Apache-2.0 ライセンスのオープンソースです。[npm の @nodaro/sdk](https://www.npmjs.com/package/@nodaro/sdk) と [GitHub 上のソース](https://github.com/nodaroai/app.nodaro.ai/tree/main/packages/client)を参照してください。
- ES モジュールと CommonJS のビルドを、TypeScript の型定義とともに提供します。
- Node.js 20 以降が必要です。また、グローバルな `fetch` と `URL` を持つランタイム、つまり最新のブラウザー、React Native、Cloudflare Workers、Deno、Bun でも動作します。
- ほかに 2 つの Nodaro パッケージが一緒にインストールされます。通信形式の型とモデルカタログを含む `@nodaro/shared` と、プロンプト用のヘルパーを含む `@nodaro/prompts` です。
- `@supabase/supabase-js` と `@supabase/ssr` は、省略可能なピア依存関係です。`supabaseAuth` または `@nodaro/sdk/supabase` を通じて Supabase でユーザーをログインさせるブラウザーアプリの場合にだけ、インストールしてください。
- [Nodaro CLI](https://nodaro.ai/docs/developers/cli) はこの SDK の上に構築されているため、CLI のコマンドと SDK の呼び出しは、同じエンドポイントを呼び出します。

## API トークンを取得する
### トークンを作成する
[Nodaro](https://app.nodaro.ai) にログインし、**設定 › APIトークン**を開いて、**トークンを作成**をクリックします。

### 表示されたときにコピーする
トークンは `ndr_` で始まり、表示されるのは 1 回だけです。Nodaro はそのハッシュしか保存しないため、なくしたトークンをもう一度表示することはできません。代わりに、新しいトークンを作成してください。

### コードに含めない
トークンは、`NODARO_TOKEN` のような環境変数か、シークレットマネージャーに保存してください。クライアント側のコードには、絶対に含めないでください。

個人用トークンは、あなた自身として動作します。ほかの人の代わりに動作させたい場合、たとえば多くのユーザーが接続するアプリでは、代わりに [OAuth](https://nodaro.ai/docs/developers/oauth) を使ってください。[認証](https://nodaro.ai/docs/developers/sdk/auth)で、すべての選択肢を比較しています。

## 最初の呼び出しをする
```ts

const client = createClient({
baseUrl: "https://app.nodaro.ai",
auth: new StaticTokenAuth(process.env.NODARO_TOKEN!),
})

const { data: nodes } = await client.nodes.list()
console.log(`${nodes.length} node types available`)
```

`client.nodes.list()` は無料で、スコープも不要なため、接続を最初に確認するのに適しています。セルフホスティング環境では、`baseUrl` に自分のインスタンスのアドレスを設定します。Nodaro と同じオリジンから配信されるブラウザーアプリでは、空文字列を使います。[クライアント](https://nodaro.ai/docs/developers/sdk/client)に、`createClient` のすべてのオプションが一覧表示されています。

## 画像を生成し、それから動画を生成する
```ts
const image = await client.nodes.runAndWait("generate-image", {
prompt: "A snow leopard resting on a rock at sunrise",
provider: "nano-banana-2",
})
console.log(image.imageUrl)

const video = await client.nodes.runAndWait("generate-video", {
prompt: "The snow leopard slowly turns its head toward the camera",
imageUrl: image.imageUrl,
provider: "seedance-2-fast",
duration: 4,
})
console.log(video.videoUrl)
```

`runAndWait` は実行を開始し、ポーリングして、ジョブの出力で解決されます。画像には `imageUrl`、動画には `videoUrl`、オーディオには `audioUrl` です。最初の呼び出しは、[**画像生成**（Generate Image）](https://nodaro.ai/docs/nodes/image/generate-image)ノードを [Nano Banana 2](https://nodaro.ai/docs/models/image/nano-banana-2) 上で実行します。2 番目の呼び出しは、その画像を[**動画生成**（Generate Video）](https://nodaro.ai/docs/nodes/video/generate-video)ノードで、[Seedance 2 Fast](https://nodaro.ai/docs/models/video/seedance-2-fast) 上でアニメーション化します。

`provider` を省略すると、ノードのデフォルトのモデルが使われます。各ノードページには、実行できるモデルとそのクレジット料金が一覧表示されており、`client.models.list()` は、同じカタログをコードから返します。[モデルとクレジット](https://nodaro.ai/docs/developers/sdk/models-and-credits)を参照してください。

## 実行の仕組み
生成は非同期です。リクエストはワーカー上で**ジョブ**を開始し、すぐに返ります。結果は、数秒後か数分後に届きます。

| 呼び出すもの | 返るもの | 次にすること |
| --- | --- | --- |
| `client.nodes.run(type, params)` | `{ jobId }` | ステータスが `completed`、`failed`、`cancelled` のいずれかになるまで、`client.jobs.getStatus(jobId)` をポーリングします。 |
| `client.nodes.runAndWait(type, params, opts)` | ジョブの出力 | 何もありません。SDK が、最大 15 分間、2 秒ごとにポーリングします。 |
| `client.nodes.runMany(type, paramsList, opts)` | リクエストごとに 1 つの `{ jobId, output }` | 何もありません。実行はまとめて開始され、結果は入力と同じ順番で返ります。 |
| `client.workflows.run(id)` | `{ executionId, status }` | 実行が終わるまで、`client.executions.get(executionId)` をポーリングします。 |

[**テキストを結合**（Combine Text）](https://nodaro.ai/docs/nodes/automate/combine-text)のような一部のノードタイプは、インラインで実行され、`jobId` なしに結果を直接返します。[ノードの実行](https://nodaro.ai/docs/developers/sdk/nodes)で、すべての実行メソッドを説明し、[ジョブと実行](https://nodaro.ai/docs/developers/sdk/jobs-and-executions)で、ステータスを説明しています。

### 進行状況を表示し、ユーザーが待つのを止められるようにする
```ts

const controller = new AbortController()
stopButton.onclick = () => controller.abort()

try {
const clip = await client.nodes.runAndWait(
"generate-video",
{ prompt: "Waves roll onto a black sand beach", provider: "seedance-2-fast", duration: 4 },
{
signal: controller.signal,
onProgress: (status) => setProgressBar(status.progress ?? 0),
},
)
showVideo(clip.videoUrl)
} catch (err) {
if (err instanceof JobAbortedError && err.jobId) {
await client.jobs.cancel(err.jobId)
} else {
throw err
}
}
```

`onProgress` は、ポーリングのたびにジョブのステータスを受け取り、モデルが報告する場合は `progress` が 0 から 100 になります。シグナルをアボートしても、待機が止まるだけです。ジョブは、`client.jobs.cancel(jobId)` でキャンセルするまで実行を続けます。このキャンセルは、確保されていたクレジットも返還します。

各結果は、届いた時点ですぐに表示してください。2 段階のフローでは、動画のステップを実行している間に、画像を表示してください。

## 認証方法を選ぶ
| プロバイダー | 使うとき | トークンの取得元 |
| --- | --- | --- |
| `StaticTokenAuth` | 1 つの固定トークンを使うサーバーのコードです | API トークン（`ndr_...`）または OAuth アクセストークン（`ndr_app_...`） |
| `CallbackAuth` | トークンの更新やローテーションを自分で行う場合です | リクエストごとに呼び出される、自分の関数です |
| `supabaseAuth` | 同じ Nodaro インスタンスにユーザーがログインするブラウザーアプリです | ユーザーの現在のセッションです |

すべてのリクエストは、プロバイダーにトークンを求め、`Authorization: Bearer <token>` として送信します。プロバイダーが `null` を返した場合、リクエストはヘッダーなしで送られます。各プロバイダーと、ブラウザー特有のルールについては、[認証](https://nodaro.ai/docs/developers/sdk/auth)を参照してください。

## エラーを処理する
API がエラーで応答すると、すべてのメソッドは `NodaroError` の型付きサブクラスをスローします。具体的なクラスから先にキャッチし、`NodaroError` は最後にキャッチしてください。

```ts

InsufficientCreditsError,
NodaroError,
RateLimitedError,
UnauthorizedError,
} from "@nodaro/sdk"

try {
await client.workflows.run(workflowId)
} catch (err) {
if (err instanceof InsufficientCreditsError) {
showPaywall({ required: err.required, available: err.available })
} else if (err instanceof UnauthorizedError) {
askForANewToken()
} else if (err instanceof RateLimitedError) {
retryLater()
} else if (err instanceof NodaroError) {
console.error(`API error ${err.status} (${err.code}): ${err.message}`)
} else {
throw err // a network failure, not an API answer
}
}
```

すべての `NodaroError` には、`message`、`insufficient_credits` のような安定した `code`、HTTP の `status` があります。[エラー](https://nodaro.ai/docs/developers/sdk/errors)に、すべてのクラスとスローされる条件が一覧表示されています。

## よく使うレシピ
### ワークフローを実行して待つ
`client.workflows.run()` は、ワークフロー内のすべてのノードを 1 回実行する**実行**を開始し、すぐに返ります。ステータスが終了状態になるまで、`client.executions.get()` をポーリングします。

```ts
const { executionId } = await client.workflows.run(workflowId)

for (;;) {
const { data } = await client.executions.get(executionId)
console.log(`${data.completedNodes}/${data.totalNodes} nodes done`)

if (["completed", "failed", "cancelled", "timed_out"].includes(data.status)) {
if (data.status !== "completed") throw new Error(data.errorMessage ?? data.status)
console.log(`Done. Used ${data.totalCreditsUsed} credits.`)
break
}
await new Promise((resolve) => setTimeout(resolve, 2_000))
}
```

一部のノードだけを実行するには、第 2 引数として `{ nodeIds: [...] }` を渡します。[ワークフローとプロジェクト](https://nodaro.ai/docs/developers/sdk/workflows)を参照してください。

### 複数の候補を一度に生成する
```ts
const results = await client.nodes.runMany("generate-image", [
{ prompt: "A lighthouse at dawn, watercolor" },
{ prompt: "A lighthouse at dusk, watercolor" },
{ prompt: "A lighthouse in a storm, watercolor" },
])
for (const { jobId, output } of results) console.log(jobId, output.imageUrl)
```

`runMany` は、いずれかの実行が失敗すると拒否されます。モデルに最も良い結果を選ばせるには、URL を [`client.reduce.run()`](https://nodaro.ai/docs/developers/sdk/llm-and-reduce) に渡します。

### ファイルをアップロードして使う
```ts
const upload = await client.uploads.upload(file) // a File, in the browser or Node.js
const portrait = await client.nodes.runAndWait("generate-image", {
prompt: "The same person as a watercolor portrait",
referenceImageUrls: [upload.url],
})
```

アップロードすると、画像、動画、オーディオの URL を受け取るどのノードにも渡せる、公開の `url` が返ります。[メディアとアップロード](https://nodaro.ai/docs/developers/sdk/media-and-uploads)を参照してください。

### 実行前に料金を確認する
```ts
const { total } = await client.credits.balance()
const { data: prices } = await client.credits.modelCosts(["nano-banana-pro", "nano-banana-pro:4K"])

if (total < prices["nano-banana-pro:4K"]) showPaywall()
```

料金と残高は、Nodaro Cloud に存在します。[モデルとクレジット](https://nodaro.ai/docs/developers/sdk/models-and-credits)と[クレジット](https://nodaro.ai/docs/concepts/credits)を参照してください。

### 生成前にプロンプトを改善する
```ts
const { prompt } = await client.promptHelper.enhance({
nodeType: "generate-image",
prompt: "snow leopard on a rock",
})
```

[プロンプトウィザード](https://nodaro.ai/docs/developers/sdk/pickers-and-prompts)は、指定したノード向けに、大まかなアイデアを詳細なプロンプトに書き直します。呼び出しごとにクレジットがかかります。

## AI コーディングアシスタントで SDK を使う
- **Claude Code プラグイン。**`/plugin marketplace add nodaroai/app.nodaro.ai` を実行し、続けて `/plugin install nodaro` を実行します。このプラグインは、SDK のパターン、モデル、クレジットを把握したスキルを追加し、Nodaro のホスト型 MCP サーバーに接続します。[エージェントスキル](https://nodaro.ai/docs/developers/agent-skills)を参照してください。
- **ほかのアシスタント。**npm のパッケージの README は、コーディングアシスタント向けに書かれた短い説明から始まります。これを、依頼内容とともに Cursor やほかのアシスタントに貼り付けてください。
- **コードをまったく書かない場合。**アシスタントに代わりに Nodaro を実行させるには、[MCP](https://nodaro.ai/docs/mcp) 経由で接続します。

## リファレンス
<Card title="クライアント" href="/docs/developers/sdk/client" description="createClient、すべてのオプション、ワークスペース、リソースの全リストです。" />
<Card title="認証" href="/docs/developers/sdk/auth" description="StaticTokenAuth、CallbackAuth、supabaseAuth、共有ブラウザーセッションです。" />
<Card title="エラー" href="/docs/developers/sdk/errors" description="すべてのエラークラスと、そのステータス、コード、復旧方法です。" />
<Card title="ノードの実行" href="/docs/developers/sdk/nodes" description="run、runAndWait、runMany を、型付きパラメーターとともに説明します。" />
<Card title="ワークフローとプロジェクト" href="/docs/developers/sdk/workflows" description="ワークフローの作成、更新、共有、エクスポート、実行です。" />
<Card title="ジョブと実行" href="/docs/developers/sdk/jobs-and-executions" description="実行のポーリング、一覧表示、キャンセル、削除です。" />

SDK は、[REST API](https://nodaro.ai/docs/developers/api) と同じエンドポイントをラップしています。まだ SDK のメソッドがないエンドポイントは、同じ認証と型付きエラーを保つ `client.request()` で呼び出してください。

## Frequently asked questions

### @nodaro/sdk とは何ですか？

Nodaro REST API の公式 TypeScript クライアントです。ノードとワークフローを実行してその結果を待ち、キャラクター、ボイス、メディアなどを管理します。すべての呼び出しに、型付きのメソッドと型付きのエラーが用意されています。

### Nodaro SDK を認証するには、どうすればよいですか？

Nodaro の「設定 › APIトークン」でトークンを作成し、環境変数に保存して、new StaticTokenAuth(token) として createClient に渡します。ブラウザーのアプリや OAuth のアプリでは、代わりに supabaseAuth または CallbackAuth を使います。

### SDK は、どのランタイムに対応していますか？

Node.js 20 以降と、グローバルな fetch と URL を持つあらゆるランタイムに対応します。たとえば、最新のブラウザー、React Native、Cloudflare Workers、Deno、Bun です。

### 結果は、自分でポーリングする必要がありますか？

いいえ。client.nodes.runAndWait が実行を開始し、そのジョブを 2 秒ごとにポーリングして、出力の URL で解決されます。完全な制御が必要な場合だけ、client.jobs.getStatus を使って自分でループを書いてください。

### セルフホスティングの Nodaro 環境でも、SDK を使えますか？

はい。baseUrl に、自分のインスタンスのアドレスを設定します。スタジオプロダクション、Recast、組織など、一部のリソースは Nodaro Cloud にしか存在せず、それ以外の環境では 404 を返します。
