ワークフローとプロジェクト
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)型
| 型 | 構造 |
|---|---|
Workflow | id、projectId、userId、name、description?、folderId?、version?、thumbnailUrl?、nodes?、edges?、settings?、sourcePrompt?、createdAt、updatedAt。グラフのフィールドがあるのは、完全なレコードだけです。 |
Project | id、userId、name、description?、settings?、createdAt、updatedAt |
Collaborator | userId、name?、avatar?、role |
WorkflowExport | export() が返し、import() が受け付ける、移植可能なバンドル |
GenericNode, GenericEdge | nodes と edges で使われる、ノードと接続の構造 |
これらの型は、すべて @nodaro/sdk からエクスポートされています。型を参照してください。
よくある質問
関連ページ
ジョブと実行
ノードの実行
ワークフロー
ワークフローとプロジェクト
インポートとエクスポート
最終更新