תהליכים ופרויקטים
יצירה, עדכון, שיתוף, ייצוא, ייבוא והרצה של תהליכי Nodaro מ-TypeScript עם client.workflows, וארגון שלהם בפרויקטים עם client.projects.
client.workflows קורא, כותב, משתף ומריץ תהליכי Nodaro, והמשאב client.projects מנהל את הפרויקטים שבהם נמצאים התהליכים. המשאב client.sessions מקבץ יצירות בודדות לסשנים בתוך פרויקט. תהליך הוא קנבס של רכיבים מחוברים, וכל תהליך שייך לפרויקט אחד. המתודות קוראות לנקודות הקצה שבדף ה-API תהליכים. ההסבר על המושגים עצמם נמצא בדף תהליכים ופרויקטים.
מתודות
| מתודה | מה היא עושה |
|---|---|
workflows.list(params) | רשימת התהליכים של פרויקט, בלי הגרפים שלהם |
workflows.get(id) | קריאה של תהליך אחד, עם הרכיבים, החיבורים וההגדרות שלו |
workflows.getPublic(id) | קריאה של תהליך ששותף בקישור, בלי אסימון |
workflows.create(input) | יצירת תהליך בפרויקט |
workflows.update(id, input) | שינוי של שדות כלשהם בתהליך |
workflows.delete(id) | מחיקת תהליך |
workflows.run(id, params?) | התחלת הרצה של התהליך |
workflows.renderFinal(id, params) | רינדור הגרסה הסופית של רינדור ברכיב החלת רשימת עריכה, אחרי בדיקת התצוגה המקדימה שלו |
workflows.estimateRenderFinal(id, params) | אומדן מחיר לאותו רינדור סופי, לפני שמתחילים אותו |
workflows.export(workflowId, opts?) | ייצוא תהליך כחבילת JSON ניידת |
workflows.import(input) | ייבוא חבילה לפרויקט |
workflows.setVisibility(id, visibility) | הגדרת תהליך כפרטי או כגלוי לסביבת העבודה שלו |
workflows.move(id, params) | העברת תהליך לפרויקט אחר |
workflows.sharedWithMe() | רשימת התהליכים שאנשים אחרים שיתפו איתכם |
workflows.listMcpConversations(params?) | רשימת שיחות ה-MCP שלכם בחודש אחד |
workflows.collaborators.* | רשימה, הוספה, שינוי והסרה של האנשים שהתהליך משותף איתם |
projects.list() ועוד | רשימה, קריאה, יצירה, עדכון ומחיקה של פרויקטים |
sessions.create(input) ועוד | סשני יצירה בתוך פרויקט, והמשימות שנמצאות בהם |
client.workflows
list(params)
מחזירה את רשימת התהליכים בפרויקט. הרשימה כוללת רק מטא־דאטה: השדות nodes, edges, settings ו-sourcePrompt מושמטים. כדי לקבל את הגרף המלא של תהליך, קראו ל-get().
list(params: { projectId: string }): Promise<{ data: Workflow[] }>מאפיין
סוג
const { data: workflows } = await client.workflows.list({ projectId })
for (const wf of workflows) console.log(wf.id, wf.name, wf.updatedAt)כשהפרויקט לא גלוי לכם, המתודה זורקת NotFoundError.
get(id)
מחזירה תהליך אחד, כולל ה-nodes, ה-edges וה-settings המלאים שלו.
get(id: string): Promise<{ data: Workflow }>מאפיין
סוג
const { data: wf } = await client.workflows.get(workflowId)
console.log(`${wf.name}: ${wf.nodes?.length ?? 0} nodes, version ${wf.version}`)שמרו את version אם אתם מתכננים לעדכן את התהליך: הערך הזה מגן על העדכון מפני שינויים במקביל של מישהו אחר.
getPublic(id)
מחזירה תהליך שהבעלים שלו שיתף בקישור (GET /v1/public/workflows/:id). לא צריך אסימון. התהליך חוזר רק כל עוד השיתוף שלו מופעל; אחרת המתודה זורקת NotFoundError. תהליך של סרטון UGC חוזר לכל אחד חוץ מהבעלים באותה צורה שבה אפליקציה שפורסמה מספקת אותו: רכיבי ה-UGC שלו, וכל רכיב שנוצר מהם, בלי התוצאות שלהם, ואף פעם לא עם התמונה של הבעלים.
getPublic(id: string): Promise<{ data: Workflow }>מאפיין
סוג
const { data: shared } = await client.workflows.getPublic(workflowId)כשספק האימות לא מחזיר אסימון, הבקשה נשלחת בלעדיו.
הפקת Studio משותפת חוזרת בלי מצב העבודה של הבעלים שלה. הפח, ההרצות שעדיין רצות, משבצות המדיה הריקות וטיוטת העורך שלא נשמרה מושמטים מ-settings.studio.
create(input)
יוצרת תהליך בפרויקט ומחזירה את הרשומה המלאה. נדרשים רק projectId ו-name; שאר השדות מקבלים את ברירות המחדל של השרת.
create(input: CreateWorkflowInput): Promise<{ data: Workflow }>מאפיין
סוג
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 }>מאפיין
סוג
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
}
}השרת מסיר מהנתונים של הרכיבים ערכים של מצב ההרצה, כגון סטטוס ההרצה או המזהה של המשימה הנוכחית, והם אף פעם לא נשמרים.
delete(id)
מוחקת תהליך.
delete(id: string): Promise<{ success: true }>מאפיין
סוג
await client.workflows.delete(workflowId)כשהמזהה לא קיים או לא שייך לכם, המתודה זורקת NotFoundError, כך שמחיקה אף פעם לא נכשלת בשקט.
run(id, params?)
מתחילה הרצה של התהליך ומחזירה מיד את { executionId, status }. ההרצה ממשיכה בשרת. כדי לקבל את ההתקדמות והתוצאה שלה, בדקו את הסטטוס מדי כמה שניות עם client.executions.get().
run(id: string, params?: {
nodeIds?: string[]
inputOverrides?: Record<string, Record<string, unknown>>
continueFromExecutionId?: string
continueMode?: "from-failed"
}, options?: { idempotencyKey?: string }): Promise<{ executionId: string; status: "pending" | "running" }>מאפיין
סוג
const { executionId } = await client.workflows.run(workflowId, {
nodeIds: ["text-prompt-1", "image-gen-2"],
})
const { data: execution } = await client.executions.get(executionId)- כשהחשבון לא יכול לכסות את העלות הגבוהה ביותר האפשרית של ההרצה, המתודה זורקת
InsufficientCreditsError. - כל עוד הרצה של התהליך הזה עדיין בעיצומה, קריאה חדשה נכשלת עם
AlreadyRunningError(409 already_running). השדהexecutionIdשבשגיאה מציין את ההרצה שאת המצב שלה כדאי לבדוק. - אסימון OAuth צריך את ההרשאה
workflows:execute. - כדי להריץ תהליך בסביבת עבודה, קראו ל-
runבלקוח שמתקבל מ-client.withWorkspace().
המשך הרצה קודמת. עם continueFromExecutionId, רצים רק הרכיבים שב-nodeIds. כל רכיב אחר מעביר הלאה את מה שההרצה הקודמת הפיקה, אף פעם לא את התוצאות השמורות של התהליך. רכיב תוכנית עריכה מעביר הלאה את התוכנית שלו, כולל השינויים שעשיתם בבדיקה, כפי שהם עכשיו. הדריסות שב-inputOverrides של ההרצה הקודמת מוחלות שוב, ואלה שאתם שולחים עכשיו מוחלות מעליהן, שדה אחר שדה.
await client.workflows.run(workflowId, {
nodeIds: [renderNodeId, captionsNodeId],
inputOverrides: { [renderNodeId]: { quality: "final" } },
continueFromExecutionId: previewRunId,
})כשהרצת המשך נדחית, המתודה זורקת שגיאה עוד לפני שנוצרת הרצה כלשהי. כשההרצה הקודמת לא נמצאת, השגיאה היא NotFoundError עם הקוד continuation_not_found. אחרת, השגיאה היא NodaroError שה-code שלה הוא continuation_subset_required (בלי nodeIds), continuation_workflow_mismatch, continuation_version_mismatch או continuation_not_completed.
המשך הרצה שנכשלה. עם continueMode: "from-failed", הפרמטר continueFromExecutionId הוא הרצה שלכם של התהליך שנכשלה, וההרצה ממשיכה מהנקודה שבה נעצרה. רצים רק הרכיבים שההרצה ההיא לא השלימה: מה שהיא השלימה מועבר הלאה, ולא רץ שוב ולא משלמים עליו שוב. רכיב שנכשל רץ שוב במלואו. הפרמטר nodeIds הוא אופציונלי: בלעדיו, ההרצה ממשיכה על הרכיבים שההרצה שנכשלה התחילה עליהם, ובנוסף על כל רכיב שנשאר במצב כשל או שעוכב. המתודה client.executions.get(id) מציינת ב-nodeScope את הרכיבים שההרצה הראשונה התחילה עליהם (null פירושו כל הרכיבים). כל מזהה ב-nodeIds נחשב לרכיב שנבחר במפורש: רכיב שמבצע עבודה ושאף הרצה בשרשרת ההרצות לא הריצה אף פעם רץ ונכלל במחיר. רכיב שרץ בהרצה כלשהי בשרשרת לא רץ שוב רק מפני שציינתם אותו. רכיבי מקור והעלאה, טריגרים, בוררים וקונטיינרים מסוג קבוצה או איסוף מעבירים הלאה את מה שההרצה העבירה, ורכיב שהוגדר לדילוג אף פעם לא רץ. שלחו idempotencyKey, כדי שניסיון חוזר של אותה קריאה לא יתחיל שום דבר חדש.
await client.workflows.run(
workflowId,
{ continueFromExecutionId: failedRunId, continueMode: "from-failed" },
{ idempotencyKey: crypto.randomUUID() }, // reuse the same key when you retry this call
)- כשמנסים להמשיך הרצה שהרצת המשך חדשה יותר החליפה, המתודה זורקת
NodaroErrorעם הקודcontinuation_superseded. ההודעה שלה מציינת את הרצת ההמשך הזו: המשיכו אותה במקומה, או מצאו שם את התוצאות שלה, אם היא השלימה הכול. - כשהרצת ההמשך החדשה ביותר נעצרה בבדיקה של תצוגה מקדימה, המתודה זורקת
ContinuationPreviewPendingError(הקודcontinuation_preview_pending, מיוצאת מ-@nodaro/sdk/errors). השדהnextשלה הוא ההרצה שמשלימה את הבדיקה: קראו קודם ל-client.workflows.run(workflowId, error.next), ואז המשיכו. - כשמנסים להמשיך הרצה שלא נכשלה, המתודה זורקת
continuation_not_failed. כשמנסים להמשיך הרצה שלא נשאר בה מה להריץ, היא זורקתcontinuation_subset_required. - כשהקרדיטים שלכם לא מכסים הרצת המשך, המתודה זורקת
InsufficientCreditsErrorעוד לפני שנוצרת הרצה כלשהי.
לכללים המלאים, ראו בדף ה-API המשך הרצה שנכשלה.
בהתקנה שבה תצוגה מקדימה עוצרת את ההרצה לבדיקה, הרצה של תהליך שרכיב החלת רשימת עריכה שלו מוגדר לתצוגה מקדימה נדחית עם 400 preview_review_required, כי אף אחד לא בודק הרצה מה-SDK. העבירו את הרינדור למצב סופי בהרצה הזו עם inputOverrides: { [renderNodeId]: { quality: "final" } }. ב-Nodaro Cloud, הרצה לא נעצרת בתצוגה מקדימה, ולכן הדחייה הזו לא קורה.
renderFinal(id, params)
מרנדרת את הגרסה הסופית של רינדור ברכיב החלת רשימת עריכה שהפיק תצוגה מקדימה, אחרי שבדקתם אותה. המתודה מריצה את מה שהכפתור רינדור סופי בעורך מריץ: את הרינדור במצב סופי בהרצה הזו בלבד, ואז את כל הרכיבים שאחריו. הרכיב שומר על ההגדרה איכות שלו. כשרכיב מחליף מצלמות נמצא בין רכיב תוכנית עריכה לרינדור, רכיב מחליף מצלמות רץ שוב קודם.
renderFinal(id: string, params: { renderNodeId: string; continueFromExecutionId: string }): Promise<{ executionId: string; status: "pending" | "running" }>מאפיין
סוג
השרת מחשב אילו רכיבים ירוצו, לפי אותו כלל שהעורך משתמש בו, ולכן שולחים רק את הרינדור ואת ההרצה הקודמת. כל רכיב שלא רץ מעביר הלאה את מה שההרצה הקודמת הפיקה.
const { executionId } = await client.workflows.renderFinal(workflowId, {
renderNodeId,
continueFromExecutionId: previewRunId,
})- מזהה של רכיב שלא קיים נדחה עם
render_final_node_not_found, ורכיב שהוא לא רינדור של החלת רשימת עריכה נדחה עםrender_final_not_a_render. גם הקודים של הרצת המשך ב-run()חלים כאן. - כשהמשלם לא יכול לכסות את ההרצה, המתודה זורקת
InsufficientCreditsError(402) עםrequiredו-available, עוד לפני שנוצרת הרצה כלשהי. - אסימון OAuth צריך את ההרשאה
workflows:execute.
estimateRenderFinal(id, params)
נותנת אומדן מחיר ל-renderFinal() ולא יוצרת שום דבר. המתודה מקבלת את אותם פרמטרים.
estimateRenderFinal(id: string, params: { renderNodeId: string; continueFromExecutionId: string }): Promise<{ data: RenderFinalQuote }>const { data: quote } = await client.workflows.estimateRenderFinal(workflowId, {
renderNodeId,
continueFromExecutionId: previewRunId,
})
if (quote.sufficient) {
await client.workflows.renderFinal(workflowId, { renderNodeId, continueFromExecutionId: previewRunId })
}לטיפוס RenderFinalQuote יש renderNodeId, nodeIds (הרכיבים שירוצו), inputOverrides (הדריסה שההרצה רצה איתה), estimatedCredits, holdCredits, sufficient ו-available. השדה holdCredits הוא מה שמשוריין להרצה בזמן הרינדור, ואף פעם לא פחות מהאומדן: קליפ UGC נכלל בו לפי השריון שלו, בערך פי שניים מהמחיר שלו. השדה sufficient מציין אם המשלם יכול לכסות את השריון הזה, והשדה available הוא הקרדיטים שזמינים למשלם להוצאה. כשתקציב של סביבת עבודה משלם, הערך של available הוא null. במהדורה בלי קרדיטים, הערכים הם null. כשההרצה מריצה רכיב LLM, אומדן המחיר מוסיף estimatedCreditsIsEstimate: true: על הרכיב הזה משלמים לפי השימוש בפועל, ולכן הציגו את הסכום כ-≈N.
export(workflowId, opts?)
מייצאת את הגרסה השמורה של תהליך כחבילת JSON ניידת, באותו פורמט קובץ שהתפריט ייצוא בעורך כותב. עם assets: true, החבילה כוללת גם את הנכסים שהתהליך משתמש בהם, כמו האפשרות עם נכסים בעורך.
export(workflowId: string, opts?: { assets?: boolean }): Promise<{ data: WorkflowExport }>מאפיין
סוג
const { data: bundle } = await client.workflows.export(workflowId, { assets: true })ניידות. חבילה יכולה להצביע רק על מדיה שמופע אחר יכול להוריד. כשרכיבים משתמשים בכתובות שמופעים אחרים לא יכולים להגיע אליהן, כגון האחסון של התקנה באירוח עצמי ב-localhost, כתובת ברשת מקומית או שם .internal, החבילה מפרטת אותן תחת portability.unreachableMedia:
bundle.portability?.unreachableMedia
// [{ nodeId: "n1", nodeLabel: "Video URL", field: "videoUrl", url: "http://localhost:3000/storage/..." }]כשכל כתובות המדיה ציבוריות, השדה לא מופיע. חבילה כזו עדיין מיובאת, אבל הרכיבים האלה לא יכולים לרוץ במופע האחר עד שמעלים לשם את המדיה שוב. ראו את המדריך ייבוא וייצוא.
import(input)
מייבאת חבילה שיוצאה לאחד הפרויקטים שלכם ומחזירה את התהליך החדש.
import(input: WorkflowExport & { projectId: string }): Promise<{
data: Workflow
importReport?: WorkflowImportReport
}>מאפיין
סוג
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 }>מאפיין
סוג
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 }[]
}>מאפיין
סוג
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)במופעים בלי ארגונים, הרשימה ריקה.
listMcpConversations(params?)
מחזירה את רשימת שיחות ה-MCP שלכם בחודש אחד, מהחדש לישן, דרך GET /v1/mcp-conversations. כל שיחה היא תהליך שעוזר AI בנה מהשלבים שלה. ראו את הדף איך שיחות MCP הופכות לתהליכים.
listMcpConversations(params?: { month?: string; sources?: string[] }): Promise<McpConversationList>- הפרמטר
monthהוא"YYYY-MM". ברירת המחדל היא החודש האחרון שיש בו שיחות. - הפרמטר
sourcesמשאיר רק חלק מהמקורות, למשל"claude","claude-code"או"chatgpt".
התוצאה כוללת את month, את months (כל חודש שיש בו שיחות, עם מספר השיחות בו), את sources (המקורות של החודש, וחיבורי ה-MCP שכל מקור מאחד) ואת data, מערך McpConversation[]. שיחה היא תהליך: פתחו אותה עם get(conversation.id).
const { data, months } = await client.workflows.listMcpConversations({ month: "2026-10", sources: ["claude-code"] })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 }>מאפיין
סוג
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שותף יכול לקרוא ל-remove() עם מזהה המשתמש שלו כדי לעזוב תהליך.
client.projects
פרויקט מקבץ תהליכים. כל תהליך שייך לפרויקט אחד בדיוק.
projects.list()
מחזירה את רשימת הפרויקטים שלכם.
list(): Promise<{ data: Project[] }>const { data: projects } = await client.projects.list()projects.get(id)
מחזירה פרויקט אחד.
get(id: string): Promise<{ data: Project }>מאפיין
סוג
const { data: project } = await client.projects.get(projectId)projects.create(input)
יוצרת פרויקט.
create(input: { name: string; description?: string; settings?: Record<string, unknown> }): Promise<{ data: Project }>מאפיין
סוג
const { data: project } = await client.projects.create({ name: "Spring campaign" })projects.update(id, input)
משנה פרויקט. שלחו לפחות שדה אחד.
update(id: string, input: { name?: string; description?: string; settings?: Record<string, unknown> }): Promise<{ data: Project }>מאפיין
סוג
await client.projects.update(projectId, { description: "Assets for the spring launch" })projects.delete(id)
מוחקת פרויקט.
delete(id: string): Promise<{ success: true }>מאפיין
סוג
await client.projects.delete(projectId)client.sessions
סשן יצירה מקבץ יצירות בודדות בתוך פרויקט, ומוצג באותה צורה בכל מכשיר. בפרויקט נמצאים הסשנים שלו, ובכל סשן נמצאים הפריטים שלו. הפרויקט של סשן נקבע כשיוצרים אותו. כל פריט הוא קישור לאחת המשימות שלכם, לא עותק.
const { data: session } = await client.sessions.create({ projectId, tool: "create-image", title: "Beach" })
// A job joins a session when the generation request names it.
await client.nodes.runAndWait("generate-image", {
prompt: "a red car",
sessionId: session.id,
origin: "create-image",
})
const { data: sessions, next } = await client.sessions.list({ projectId })
const { data: items } = await client.sessions.items(session.id)| מתודה | חתימה | הערות |
|---|---|---|
create | create(input: CreateSessionInput): Promise<{ data: GenerationSession }> | השדה tool נדרש, למשל create-image. השדות projectId ו-title אופציונליים. |
list | list(params?: ListSessionsParams): Promise<SessionPage<GenerationSession>> | מהחדש לישן. מסננים: projectId ("none" לסשנים שלא שייכים לאף פרויקט), tool, includeArchived, limit ו-cursor. כל סשן כולל את itemCount (הפריטים הפעילים), removedCount (הפריטים בפח), coverJobId ועד ארבע כתובות ב-previewUrls (תמונת השער קודם, כשהיא מוגדרת). |
get | get(id: string): Promise<{ data: GenerationSession }> | סשן אחד. |
update | update(id: string, input: UpdateSessionInput): Promise<{ data: GenerationSession }> | השדות title (הערך null משאיר את הסשן ללא שם), archived ו-coverJobId (אחד הפריטים של הסשן, אחרת 404; הערך null פירושו בחירה אוטומטית). אי אפשר לשנות את הפרויקט. |
delete | delete(id: string): Promise<{ success: true }> | מוחקת את הסשן. המשימות שלו נשמרות, ונשארות בכל סשן אחר שהן נמצאות בו. |
items | items(id: string, params?: ListSessionItemsParams): Promise<SessionPage<SessionItem>> | הפיד של הפריטים הפעילים, מהחדש לישן. לכל פריט יש jobId, addedAt, removedAt, imported, importedFrom ו-job. עם { removed: true } מוחזרים במקום זאת הפריטים שהוסרו מהסשן, כלומר הפח של הסשן, מההסרה האחרונה לראשונה. |
importItems | importItems(id: string, input: { jobIds: string[] }): Promise<{ data: { imported: number; requested: number } }> | מקשרת לסשן עד 100 מהמשימות הפעילות שלכם. זה הכול או כלום: משימה אחת שלא שייכת לכם מכשילה את הקריאה עם 404. פריט שהוסר מהסשן חוזר למקום שבו היה. |
moveItems | moveItems(targetId: string, input: MoveSessionItemsInput): Promise<{ data: { moved: number } }> | { jobIds, fromSessionId }, בטרנזקציה אחת. סשן היעד מקבל את הפריטים, וסשן המקור שומר אותם כפריטים שהוסרו, כך שהמתודה restoreItem(fromSessionId, jobId) מבטלת את ההעברה. זה הכול או כלום: 404 כשמזהה כלשהו הוא לא פריט פעיל בסשן המקור. |
removeItem | removeItem(id: string, jobId: string, options?: { forever?: boolean }): Promise<{ success: true }> | מעבירה את הפריט לפח של הסשן, עד שמשחזרים אותו. שום דבר לא מתנקה אוטומטית. המשימה, וכל סשן אחר שהיא נמצאת בו, נשארים. עם { forever: true }, המתודה מוחקת לצמיתות פריט שכבר הוסר, ועל פריט פעיל היא זורקת NodaroError עם 409 ו-not_in_trash. |
restoreItem | restoreItem(id: string, jobId: string): Promise<{ success: true }> | מחזירה פריט שהוסר לסשן, למקום שבו היה. |
הפרויקט של סשן קבוע, ולכן כדי להעביר פריטים לפרויקט אחר, מעבירים אותם לסשן של אותו פרויקט: קראו ל-moveItems() על סשן שם. פריט שכבר לא נמצא באף סשן מופיע תחת כללי: client.jobs.list({ inSession: false }).
client.trash
בפח נמצאים הפריטים שהסרתם מסשנים והמשימות שמחקתם. כלי יצירה מציג אותו כרשומה אחת לצד כללי. ראו בדף ה-API הפח.
list(params?: ListTrashParams): Promise<TrashPage> // GET /v1/trash
interface ListTrashParams {
projectId?: string | "none" // a project, or the sessions with no project and General
tool?: string // what a session of this tool holds or held
type?: string | string[] // input_data.type, like jobs.list
limit?: number // 1–100 (default 50)
cursor?: string // the previous page's next
}
type TrashEntry =
| { kind: "removed"; removedAt: string; session: TrashSession; job: Job }
| { kind: "deleted"; deletedAt: string; purgeAt: string; job: Job }הרשימה מסודרת מהחדש לישן. פריט שהוסר נשאר עד שקוראים ל-sessions.restoreItem(session.id, job.id) או ל-sessions.removeItem(session.id, job.id, { forever: true }). משימה שנמחקה נשארת עד purgeAt, 30 ימים אחרי deletedAt, ואז נמחקת לצמיתות. עותק שנשמר בספרייה נשאר. המתודה jobs.restore(job.id) מחזירה אותה לכל סשן שהיא הייתה בו, והמתודה jobs.delete(job.id, { forever: true }) מוחקת אותה מיד. פריט שהוסר, ושגם את המשימה שלו מחקתם, מופיע פעם אחת, כמשימה שנמחקה. למשימה שאף פעם לא הייתה בסשן אין כלי, ולכן הסינון לפי tool משמיט אותה: כדי לכלול אותה, שלחו type עם סוגי המשימות של הכלי שלכם.
const { data: trash } = await client.trash.list({ projectId, type: ["generate-image", "image-edit"] })
for (const entry of trash) {
if (entry.kind === "deleted") await client.jobs.restore(entry.job.id)
else await client.sessions.restoreItem(entry.session.id, entry.job.id)
}כל בקשה שיוצרת משימה מקבלת sessionId ו-origin, והפלטפורמה רושמת אותם במשימה. הם מופיעים בטיפוסים של כל פרמטרי היצירה, כגון GenerateImageParams, GenerateVideoParams ו-TextToSpeechParams, ובקלטי ה-generate* של דמויות, אובייקטים, מיקומים ויצורים. הערך של origin חייב להיות slug: אותיות לטיניות קטנות, ספרות ומקפים, עד 40 תווים. כל ערך אחר נדחה עם 400 validation_error. השדה session_id של משימה מופיע ב-client.jobs.get() וב-client.jobs.list().
טיפוסים
| טיפוס | מבנה |
|---|---|
Workflow | id, projectId, userId, name, description?, folderId?, version?, thumbnailUrl?, nodes?, edges?, settings?, sourcePrompt?, createdAt, updatedAt. שדות הגרף מופיעים רק ברשומות מלאות. |
RunWorkflowParams | nodeIds?, inputOverrides?, continueFromExecutionId? |
RenderFinalParams | renderNodeId, continueFromExecutionId |
RenderFinalQuote | renderNodeId, nodeIds, inputOverrides, estimatedCredits, estimatedCreditsIsEstimate?, holdCredits, sufficient, available |
Project | id, userId, name, description?, settings?, createdAt, updatedAt |
GenerationSession, SessionItem, SessionPage | סשן יצירה, פריט אחד שלו ועמוד של כל אחד מהם |
Collaborator | userId, name?, avatar?, role |
WorkflowExport | החבילה הניידת שהמתודה export() מחזירה והמתודה import() מקבלת |
GenericNode, GenericEdge | המבנים של רכיב ושל חיבור שמשמשים ב-nodes וב-edges |
כולם מיוצאים מ-@nodaro/sdk. ראו את הדף טיפוסים.
שאלות נפוצות
איך מריצים תהליך Nodaro מקוד?
קראו למתודה client.workflows.run עם מזהה התהליך. המתודה מחזירה מיד executionId. בדקו את הסטטוס מדי כמה שניות עם המתודה client.executions.get ועם ה-executionId, עד שהסטטוס הוא completed, failed, cancelled או timed_out.
האם אפשר להריץ רק חלק מהרכיבים של תהליך?
כן. העבירו לארגומנט השני של המתודה client.workflows.run אובייקט עם nodeIds, רשימת המזהים של הרכיבים שרוצים להריץ. רק הרכיבים האלה רצים.
איך מרנדרים מקוד את הגרסה הסופית של תצוגה מקדימה?
קראו למתודה client.workflows.renderFinal עם המזהה של רכיב החלת רשימת עריכה שמבצע את הרינדור, ועם המזהה של ההרצה שהפיקה את התצוגה המקדימה. המתודה מריצה את הרינדור במצב סופי ואת כל הרכיבים שאחריו. המתודה client.workflows.estimateRenderFinal נותנת אומדן מחיר לפני כן.
איך נמנעים מדריסה של שינויים שמישהו אחר עשה?
העבירו למתודה client.workflows.update את expectedVersion, הגרסה שקראתם. אם התהליך השתנה בינתיים, המתודה זורקת WorkflowConflictError עם הרשומה הנוכחית, כך שאפשר למזג ולנסות שוב.
איך מעתיקים תהליך למופע Nodaro אחר?
ייצאו את התהליך עם המתודה client.workflows.export, כשהאפשרות assets מוגדרת ל-true, ואז ייבאו את החבילה במופע האחר עם המתודה client.workflows.import ועם projectId. מדיה נגישה מועתקת לאחסון של המופע החדש.
דפים קשורים
משימות והרצות
הרצת רכיבים
תהליכים
תהליכים ופרויקטים
ייבוא וייצוא
עודכן לאחרונה