Nodaro ドキュメント
ドキュメントノードリファレンスモデルAI エージェント(MCP)開発者向けセルフホスティングリサーチ
TypeScript SDK

ワークフローとプロジェクト

client.workflows を使って、TypeScript から Nodaro のワークフローを作成、更新、共有、エクスポート、インポート、実行し、client.projects でプロジェクトに整理します。

client.workflows は Nodaro のワークフローの読み取り、書き込み、共有、実行を行い、client.projects はワークフローを入れるプロジェクトを管理します。ワークフローは接続されたノードからなるキャンバスで、どのワークフローも 1 つのプロジェクトに属します。これらのメソッドは、ワークフローの REST API と同じエンドポイントを呼び出します。概念については、ワークフローとプロジェクトを参照してください。

メソッド

メソッド内容
workflows.list(params)プロジェクトのワークフローを、グラフを除いて一覧表示します
workflows.get(id)1 つのワークフローを、ノード、接続、設定とともに読み取ります
workflows.getPublic(id)リンクで共有されたワークフローを、トークンなしで読み取ります
workflows.create(input)プロジェクトにワークフローを作成します
workflows.update(id, input)ワークフローの任意のフィールドを変更します
workflows.delete(id)ワークフローを削除します
workflows.run(id, params?)ワークフローの実行を開始します
workflows.export(workflowId, opts?)ワークフローを、移植可能な JSON バンドルとしてエクスポートします
workflows.import(input)バンドルをプロジェクトにインポートします
workflows.setVisibility(id, visibility)ワークフローを非公開にするか、ワークスペースに公開します
workflows.move(id, params)ワークフローを別のプロジェクトに移動します
workflows.sharedWithMe()ほかの人から共有されたワークフローを一覧表示します
workflows.collaborators.*ワークフローの共有相手を一覧表示、追加、変更、削除します
projects.list() ほかプロジェクトを一覧表示、読み取り、作成、更新、削除します

client.workflows

list(params)

プロジェクト内のワークフローを一覧表示します。一覧で返されるのはメタデータだけで、nodes、edges、settings、sourcePrompt は含まれません。グラフ全体を取得するには、get() で 1 つのワークフローを読み取ります。

list(params: { projectId: string }): Promise<{ data: Workflow[] }>

Prop

Type

const { data: workflows } = await client.workflows.list({ projectId })
for (const wf of workflows) console.log(wf.id, wf.name, wf.updatedAt)

あなたから見えないプロジェクトを指定すると、NotFoundError をスローします。

get(id)

1 つのワークフローを、完全な nodes、edges、settings を含めて読み取ります。

get(id: string): Promise<{ data: Workflow }>

Prop

Type

const { data: wf } = await client.workflows.get(workflowId)
console.log(`${wf.name}: ${wf.nodes?.length ?? 0} nodes, version ${wf.version}`)

ワークフローを更新する予定がある場合は、version を保持しておいてください。version を使うと、ほかの人の書き込みがあっても、安全に更新できます。

getPublic(id)

所有者がリンクで共有したワークフローを読み取ります(GET /v1/public/workflows/:id)。トークンは不要です。ワークフローが返されるのは、共有がオンになっている間だけです。オフの場合、このメソッドは NotFoundError をスローします。

getPublic(id: string): Promise<{ data: Workflow }>

Prop

Type

const { data: shared } = await client.workflows.getPublic(workflowId)

認証プロバイダーがトークンを返さない場合、リクエストはトークンなしで送られます。

create(input)

プロジェクトにワークフローを作成し、完全なレコードを返します。必要なのは projectId と name だけで、ほかのフィールドにはサーバーのデフォルト値が使われます。

create(input: CreateWorkflowInput): Promise<{ data: Workflow }>

Prop

Type

const { data: wf } = await client.workflows.create({
  projectId,
  name: "Product launch video",
  nodes: [],
  edges: [],
})

できあがったグラフを使うには、エディターで作ったワークフローをエクスポートして、その nodes と edges を読み取るか、テンプレートを複製します。

update(id, input)

ワークフローのフィールドを任意の組み合わせで変更し、更新後の完全なレコードを返します(PATCH /v1/workflows/:id)。指定しなかったフィールドは、そのまま残ります。

update(id: string, input: UpdateWorkflowInput): Promise<{ data: Workflow }>

Prop

Type

await client.workflows.update(workflowId, { name: "Renamed", expectedVersion: 7 })

安全な更新:expectedVersion も expectedUpdatedAt も指定しない場合は、最後の書き込みが優先されます。どちらかを指定すると、読み取った後に誰もワークフローを変更していない場合にだけ、更新が適用されます。変更されていた場合は WorkflowConflictError をスローします。その currentRecord には現在のワークフローが入っているので、もう一度読み取らずにマージできます。

import { WorkflowConflictError } from "@nodaro/sdk"

try {
  await client.workflows.update(workflowId, { settings, expectedVersion: wf.version })
} catch (err) {
  if (err instanceof WorkflowConflictError && err.currentRecord) {
    const merged = mergeSettings(err.currentRecord.settings, settings)
    await client.workflows.update(workflowId, {
      settings: merged,
      expectedVersion: err.currentVersion,
    })
  } else {
    throw err
  }
}

ノードデータにある実行状態の値(実行中のステータスや、現在のジョブ ID など)は、サーバーによって削除され、保存されることはありません。

delete(id)

ワークフローを削除します。

delete(id: string): Promise<{ success: true }>

Prop

Type

await client.workflows.delete(workflowId)

ID が存在しない場合や、あなたのものではない場合は、NotFoundError をスローします。そのため、削除が何も知らせずに失敗することはありません。

run(id, params?)

ワークフローの実行を開始し、すぐに { executionId, status } を返します。実行は、サーバー上で続きます。進行状況と結果は、client.executions.get() をポーリングして取得します。

run(id: string, params?: { nodeIds?: string[] }): Promise<{ executionId: string; status: "pending" | "running" }>

Prop

Type

const { executionId } = await client.workflows.run(workflowId, {
  nodeIds: ["text-prompt-1", "image-gen-2"],
})
const { data: execution } = await client.executions.get(executionId)
  • アカウントの残高が、実行にかかりうる最大の料金に足りない場合は、InsufficientCreditsError をスローします。
  • OAuth トークンには、workflows:execute スコープが必要です。
  • ワークスペース内のワークフローを実行するには、client.withWorkspace() で得たクライアントで run を呼び出します。

export(workflowId, opts?)

ワークフローの保存済みのバージョンを、移植可能な JSON バンドルとしてエクスポートします。これは、エディターのエクスポートメニューが書き出すのと同じファイル形式です。assets: true を指定すると、エディターのアセットを含めると同じように、ワークフローが使うアセットもバンドルに含まれます。

export(workflowId: string, opts?: { assets?: boolean }): Promise<{ data: WorkflowExport }>

Prop

Type

const { data: bundle } = await client.workflows.export(workflowId, { assets: true })

移植性:バンドルが参照できるのは、ほかのインスタンスが取得できるメディアだけです。ほかのインスタンスからアクセスできない URL をノードが使っている場合、バンドルはそれらを portability.unreachableMedia に列挙します。たとえば、localhost 上にあるセルフホスティング環境自身のストレージ、ローカルネットワークのアドレス、.internal の名前などです。

bundle.portability?.unreachableMedia
// [{ nodeId: "n1", nodeLabel: "Video URL", field: "videoUrl", url: "http://localhost:3000/storage/..." }]

すべてのメディアの URL が公開されている場合、このフィールドはありません。アクセスできないメディアを含むバンドルもインポートはできますが、該当するノードは、メディアをアップロードし直すまで、インポート先のインスタンスでは実行できません。インポートとエクスポートを参照してください。

import(input)

エクスポートしたバンドルを、自分のプロジェクトのいずれかにインポートし、新しいワークフローを返します。

import(input: WorkflowExport & { projectId: string }): Promise<{
  data: Workflow
  importReport?: WorkflowImportReport
}>

Prop

Type

const { data: wf, importReport } = await client.workflows.import({ ...bundle, projectId })

インポートでは、次の処理が行われます。

  • アセットが作成し直されます:バンドル内のキャラクター、オブジェクト、クリーチャー、ロケーションは、あなたのアカウントの新しい項目になります。ワークフローの参照先も、それらに付け替えられます。対象は、アセットノード、ノードデータ内のすべての @ メンション、ワークフローの設定です。
  • メディアがコピーされます:ほかのホストにあるメディアは、アクセスできる場合、このインスタンスのストレージにコピーされます。そのため、ワークフローがほかの人のサーバーに依存することはありません。上限は、ワークフローのメディアで 25 ファイル、同梱のアセットでさらに 25 ファイルです。画像は 20 MB まで、動画とオーディオは 50 MB までです。
  • コピーはストレージの使用量に含まれます:ストレージが足りなくなっても、ワークフロー自体はインポートされ、収まらなかったアセットはレポートに一覧表示されます。

importReport は、何が起きたかを示します。

importReport
// {
//   rehosted: 3,                                    // files copied to this instance
//   unreachable: [{ nodeId, nodeLabel, field, url }], // private hosts, left as they were
//   skipped: [{ nodeId, field, url, reason: "HTTP 404" }],
//   assetIdMap: { "<bundled asset id>": "<new asset id>" },
//   assetsSkipped: [{ kind: "character", id, name: "Kira", reason: "Storage limit exceeded" }],
// }

assetIdMap は、バンドルがアセットを含んでいた場合に必ず存在します。ワークフロー内のメンションは、サーバーがすでにすべて更新しています。このマップは、ワークフローの外で保持している参照にだけ使ってください。assetsSkipped が含まれるのは、何かが除外された場合だけです。

setVisibility(id, visibility)

ワークフローを、作成者と追加した共同編集者だけが見られる "private" にするか、ワークスペースの全員が見られる "workspace" にします。

setVisibility(id: string, visibility: "private" | "workspace"): Promise<{ data: Workflow }>

Prop

Type

await client.workflows.setVisibility(workflowId, "workspace")

変更できるのは、作成者かワークスペースの管理者だけです。それ以外の人が変更しようとすると、ForbiddenError がスローされます。ワークスペースは、Nodaro Cloud の組織にあります。

move(id, params)

ワークフローを別のプロジェクトに移動します(POST /v1/workflows/:id/move)。ワークフローは、元のフォルダーから外れます。

move(id: string, params: { projectId: string }): Promise<{
  data: Workflow
  droppedCollaborators: { userId: string; name: string | null }[]
}>

Prop

Type

const { droppedCollaborators } = await client.workflows.move(workflowId, { projectId: archiveProjectId })

移動によってワークフローがワークスペースの外に出る場合、そのワークスペースから得ていたアクセス権はなくなります。アクセス権を失った人は、droppedCollaborators で返されます。

sharedWithMe()

ほかの人があなたに直接共有したワークフローを一覧表示します。所属しているワークスペース内の作品は、そのワークスペース自身の一覧にすでに表示されるため、含まれません。各ワークフローには、あなたがそのワークフローに対して持つ grantedRole が付いています。

sharedWithMe(): Promise<{ data: (Workflow & { grantedRole: "viewer" | "editor" })[] }>
const { data: shared } = await client.workflows.sharedWithMe()
for (const wf of shared) console.log(wf.name, wf.grantedRole)

組織のないインスタンスでは、この一覧は空です。

collaborators

ワークフローの共有相手です。client.workflows.collaborators からアクセスします。これらのメソッドは、組織のあるインスタンスで使えます。それ以外のインスタンスでは、NotFoundError をスローします。

collaborators.list(workflowId: string): Promise<{ data: Collaborator[] }>
collaborators.add(workflowId: string, input: { userId?: string; email?: string; role: "viewer" | "editor" }): Promise<{ data: { userId: string; role: "viewer" | "editor" } }>
collaborators.update(workflowId: string, userId: string, input: { role: "viewer" | "editor" }): Promise<{ data: { userId: string; role: "viewer" | "editor" } }>
collaborators.remove(workflowId: string, userId: string): Promise<{ success: true }>

Prop

Type

await client.workflows.collaborators.add(workflowId, { email: "editor@example.com", role: "editor" })

const { data: people } = await client.workflows.collaborators.list(workflowId)
// [{ userId, name, avatar, role }]: email addresses are never returned

共同編集者は、自分のユーザー ID を指定して remove() を呼び出すと、ワークフローから抜けられます。

client.projects

プロジェクトは、ワークフローをまとめるものです。どのワークフローも、ちょうど 1 つのプロジェクトに属します。

projects.list()

自分のプロジェクトを一覧表示します。

list(): Promise<{ data: Project[] }>
const { data: projects } = await client.projects.list()

projects.get(id)

1 つのプロジェクトを読み取ります。

get(id: string): Promise<{ data: Project }>

Prop

Type

const { data: project } = await client.projects.get(projectId)

projects.create(input)

プロジェクトを作成します。

create(input: { name: string; description?: string; settings?: Record<string, unknown> }): Promise<{ data: Project }>

Prop

Type

const { data: project } = await client.projects.create({ name: "Spring campaign" })

projects.update(id, input)

プロジェクトを変更します。少なくとも 1 つのフィールドを渡してください。

update(id: string, input: { name?: string; description?: string; settings?: Record<string, unknown> }): Promise<{ data: Project }>

Prop

Type

await client.projects.update(projectId, { description: "Assets for the spring launch" })

projects.delete(id)

プロジェクトを削除します。

delete(id: string): Promise<{ success: true }>

Prop

Type

await client.projects.delete(projectId)

型

型構造
Workflowid、projectId、userId、name、description?、folderId?、version?、thumbnailUrl?、nodes?、edges?、settings?、sourcePrompt?、createdAt、updatedAt。グラフのフィールドがあるのは、完全なレコードだけです。
Projectid、userId、name、description?、settings?、createdAt、updatedAt
CollaboratoruserId、name?、avatar?、role
WorkflowExportexport() が返し、import() が受け付ける、移植可能なバンドル
GenericNode, GenericEdgenodes と edges で使われる、ノードと接続の構造

これらの型は、すべて @nodaro/sdk からエクスポートされています。型を参照してください。

よくある質問

最終更新

目次