משימות והרצות
תשאול, רשימה, דירוג, ביטול ומחיקה של הרצות Nodaro מ-TypeScript, בדיקת המצב של הרצות תהליכים וקבלת קריאות Webhook חתומות כשמשימה מסתיימת.
משימה היא יצירה אחת ב-Nodaro, כגון תמונה אחת, רינדור אחד של סרטון או קריינות אחת, ורשומת הרצה מייצגת הרצה אחת של תהליך שלם. המשאב client.jobs קורא משימות, מחזיר רשימות שלהן, מבטל אותן ומוחק אותן, והמשאב client.executions קורא הרצות של תהליכים, מחזיר רשימות שלהן ומבטל אותן. המשאב client.webhooks רושם נקודות קצה ש-Nodaro קורא להן כשמשימה מסתיימת. המשאב client.videoPro עוצר או ממשיך הרצה ארוכה של רכיב יצירת וידאו Pro. המתודות קוראות לנקודות הקצה שבדפי ה-API משימות והרצות.
מתודות
| מתודה | מה היא עושה |
|---|---|
executions.get(id) | קריאה של הרצת תהליך, עם המצב של כל רכיב |
executions.listForWorkflow(workflowId, params?) | רשימת ההרצות של תהליך |
executions.cancel(id, params?) | עצירה של הרצת תהליך |
jobs.get(id) | קריאה של משימה, עם הקלט והפלט שלה |
jobs.list(params?) | רשימת המשימות שלכם, מהחדש לישן |
jobs.rate(id, rating) | דירוג של אחת מהמשימות שלכם כ-good או כ-bad, או מחיקת הדירוג |
jobs.fromUpload(params) | רישום של תמונה שנערכה בדפדפן כמשימה |
jobs.getStatus(id) | קריאת הסטטוס של משימה, לתשאול |
jobs.cancel(id) | עצירה של משימה והחזר של הקרדיטים ששוריינו לה |
jobs.delete(id, options?) ו-jobs.restore(id) | העברה של משימה לפח, שחזור שלה או מחיקה לצמיתות |
webhooks.create(input) ועוד | רישום, שינוי, בדיקה וביקורת של נקודות הקצה ש-Nodaro קורא להן כשמשימה מסתיימת |
verifyWebhookSignature(options) | בדיקת החתימה של קריאה שנקודת הקצה שלכם קיבלה |
videoPro.stop(jobId) | עצירת הרצה של רכיב יצירת וידאו Pro ושמירת מה שכבר הסתיים |
videoPro.continueRun(jobId, opts?) | הרצת המשך להרצה של רכיב יצירת וידאו Pro, כמשימה חדשה |
סטטוסים
משימה עוברת בין הסטטוסים האלה:
| סטטוס משימה | משמעות |
|---|---|
pending, queued | ממתינה ל-worker. |
processing | רצה. השדה progress עולה מ-0 עד 100 כשהמודל מדווח על התקדמות. |
pending_review | מדיניות תוכן של הפריסה הזו מעכבת אותה עד שאדם יבדוק אותה. זה לא סטטוס סופי. |
completed | הסתיימה. התוצאה נמצאת ב-output_data. |
failed | נכשלה. השדה error_message מסביר למה, והשדה error_hint עשוי לסווג את הכשל. |
cancelled | בוטלה. |
לרשומת הרצה יש סטטוסים משלה: pending, running, completed, failed, cancelled, stopping, timed_out ו-discarded. כל רכיב בתוכה נמצא באחד המצבים pending, running, completed, failed או skipped.
client.executions
רשומת הרצה מייצגת הרצה אחת של תהליך. היא מקבצת משימה אחת לכל רכיב AI, ואת המצב של כל רכיב.
executions.get(id)
מחזירה הרצת תהליך, כולל מפה של המצב של כל רכיב. כשהמזהה שייך למשימה של רכיב יחיד ולא להרצת תהליך, השרת עונה באותו מבנה, בשביל הרכיב האחד הזה.
get(id: string): Promise<{ data: WorkflowExecution }>מאפיין
סוג
const { data } = await client.executions.get(executionId)
console.log(data.status, `${data.completedNodes}/${data.totalNodes}`, data.totalCreditsUsed)ב-WorkflowExecution נמצאים השדות id, kind, workflowId, status, outcome, triggerType (manual, webhook, schedule, app_run, single-node, telegram, telegram_account, api או mcp), nodeStates, totalNodes, completedNodes, failedNodes, totalCreditsUsed, errorMessage, startedAt, completedAt, createdAt ו-updatedAt. הערך של kind הוא execution בהרצת תהליך, ו-job במשימה של רכיב יחיד. במשימה של רכיב יחיד שלקוח MCP התחיל, השדה triggerType הוא mcp.
הרצות שלא מוצאות שום דבר חדש. הרצה שלא מצאה שום דבר חדש מסתיימת בסטטוס completed, ולא failed. למשל, פיד לא מצא פוסטים חדשים, ולכן לרכיב שכותב אחריו לא היה על מה לכתוב. כשרכיב צריך טקסט, והטקסט שמחובר אליו מגיע מרכיב שלא הפיק כלום בהרצה הזו, מדלגים על הרכיב, והערך של nodeStates[id].skipReason הוא "empty_input". אז ההרצה שהסתיימה מקבלת outcome: "nothing_new". בכל הרצה אחרת שהסתיימה, השדה outcome הוא "succeeded". עד שההרצה מסתיימת, השדה outcome לא מופיע.
import { executionOutcome, countEmptyInputSkips } from "@nodaro/sdk"
const { data } = await client.executions.get(executionId)
if (data.outcome === "nothing_new") {
console.log(`Nothing new: ${countEmptyInputSkips(data.nodeStates)} node(s) had nothing to work on`)
}
executionOutcome(data.status, data.nodeStates) // the same answer, worked out in your codeקריאת הפלט של רכיב. השדה nodeStates[nodeId].output מופיע כשהרכיב בסטטוס completed. הוא יכול להופיע גם כשהרכיב בסטטוס failed, אבל ההרצה שמרה תוצאה שאפשר להשתמש בה, כמו שעושים הרכיבים שבונים סצנות תלת־ממד. בדקו אם השדה קיים, ולא את הסטטוס, ואף פעם אל תתייחסו ל-output קיים כאל הצלחה:
import { nodeStateMayCarryOutput } from "@nodaro/sdk"
const node = data.nodeStates["scene-1"]
if (node.status === "failed") {
console.error(node.error) // the failure stands
if (node.output?.plan) {
// the draft the run kept is still here, and it was billed
}
}
nodeStateMayCarryOutput(node.status) // true for "completed" and "failed"גם הקבוע OUTPUT_BEARING_NODE_STATUSES, הקבוצה של שני הסטטוסים האלה, מיוצא.
executions.listForWorkflow(workflowId, params?)
מחזירה את ההרצות של תהליך אחד, מהחדש לישן, עמוד אחד בכל פעם. ברשימה מופיעות גם הרצות של רכיב יחיד שהתחילו בתהליך הזה.
listForWorkflow(workflowId: string, params?: ListExecutionsForWorkflowParams): Promise<{
data: WorkflowExecutionSummary[]
nextCursor?: string
}>מאפיין
סוג
const { data: runs, nextCursor } = await client.executions.listForWorkflow(workflowId, {
limit: 20,
status: "completed",
})כל WorkflowExecutionSummary כולל את אותם kind ו-outcome כמו get().
executions.cancel(id, params?)
עוצרת הרצת תהליך. יש שלוש דרכים לעצור אותה:
- מיד (ברירת המחדל): המשימות שרצות מבוטלות, הקרדיטים ששוריינו להן מוחזרים, והסטטוס הופך ל-
cancelled. גם משימת LLM שמחויבת לפי השימוש ורצה באותו רגע מבוטלת, אבל נגבים עליה הקרדיטים שהספק כבר חייב עליהם, ושאר הקרדיטים ששוריינו לה מוחזרים. על משימה כזו שנעצרה לפני שהקריאה שלה התחילה מקבלים החזר, חוץ ממה שניסיון קודם של אותה משימה כבר השתמש בו. mode: "after_current": הסטטוס הופך ל-stopping. הרכיבים שרצים מסתיימים, והתוצאות שלהם מופיעות על הקנבס ובספרייה שלכם, ואז ההרצה נעצרת.mode: "discard": רכיבים חדשים לא מתחילים, אבל המשימות שרצות לא מבוטלות, כי אי אפשר לעצור באמצע קריאה למודל חיצוני. המשימות מסתיימות ונשמרות בספרייה שלכם, אבל התוצאות שלהן לא חוזרות לקנבס. הסטטוס הופך ל-discarded, והקרדיטים לא מוחזרים, כי המשימות הושלמו.
cancel(id: string, params?: { mode?: "after_current" | "discard" }): Promise<{ success: true }>מאפיין
סוג
await client.executions.cancel(executionId, { mode: "after_current" })client.jobs
משימה היא יצירה אחת: תמונה אחת, רינדור אחד של סרטון, קריינות אחת. הרצת תהליך יוצרת משימה אחת לכל רכיב AI, וכל הרצה של רכיב יחיד יוצרת משימה אחת. השדות של משימה כתובים ב-snake_case, כמו שה-API שולח אותם.
jobs.get(id)
מחזירה משימה, כולל הקלט והפלט שלה.
get(id: string): Promise<{ data: Job }>מאפיין
סוג
const { data: job } = await client.jobs.get(jobId)
if (job.status === "completed") console.log(job.output_data)השדות של Job:
| שדה | תיאור |
|---|---|
id, status, progress | מזהה המשימה, הסטטוס שלה וההתקדמות שלה, מ-0 עד 100. |
input_data, output_data | הבקשה והתוצאה. ערכים שמיועדים לשרת בלבד מושמטים משניהם. |
error_message | למה המשימה נכשלה, או null. |
error_hint | סיבה מובנית לחלק מהכשלים. ראו בהמשך. |
credits | הקרדיטים ששוריינו למשימה, או null. |
credit_status | מה מצב הקרדיטים: reserved, committed או refunded. הערך הוא null במשימה שאין עליה חיוב. |
credits_charged | כמה המשימה עלתה אחרי החיוב הסופי של השריון שלה, כולל השלבים שהיא הריצה. במשימה שמריצה בשבילכם משימות אחרות, כגון הכנת הייחוס, המסכה והסרטון בהרצה של Nodaro Motion, הקרדיטים על כל שלב נגבים ברגע שהחיוב של השלב נסגר. הערך יכול להיות נמוך מהשריון. כשהקרדיטים ששוריינו להרצה עצמה הוחזרו, הערך הוא 0 ועוד הקרדיטים שנגבו על שלבים שהחיוב שלהם כבר נסגר. הערך הוא null כל עוד השריון של המשימה עצמה פתוח, גם כשהחיוב של חלק מהשלבים כבר נסגר, כששום דבר בהרצה לא שוריין או כשלרגע אי אפשר היה לקרוא את השלבים שלה. כדי לחשב כמה הוצאתם, סכמו את השדה הזה. |
credits_held | השריון של ההרצה: הערך של credits ועוד השריונות של השלבים. |
credits_released | מה שחזר מ-credits_held אחרי החיוב הסופי של כל השריונות בהרצה, או null עד אז. |
job_type | סוג המשימה. |
created_at, started_at, completed_at | חותמות זמן. |
user_id | הבעלים. |
source, source_detail | מאיפה המשימה הגיעה: sdk, cli, mcp, app, web, api ועוד, עם פירוט כגון sdk/2.17.0. |
recovering | הערך הוא true בזמן שהפלטפורמה מתקנת משימה שה-worker שלה נעצר אחרי שהמודל כבר מסר את התוצאה. |
favorited | האם המשימה מסומנת כמועדפת אצל הבעלים שלה. ראו את הסעיף client.gallery בדף מדיה והעלאות. |
rating | "good", "bad" או null. ראו את הסעיף jobs.rate(). |
session_id | סשן היצירה שבו המשימה נוצרה, או null. |
כשלרגע השרת לא מצליח לקרוא את favorited ואת rating, הוא משמיט אותם. התייחסו לשדה חסר כ״לא ידוע״, ואף פעם לא כ-false.
השדה output_data של משימת תמונה כולל את גודל התמונה בפיקסלים: השדות width ו-height של imageUrl, ו-images ({ url, width, height } לכל פריט) לצד imageUrls. השדות האלה לא מופיעים במשימות ישנות יותר. הטיפוס של Job.output_data הוא unknown, ולכן כדי לקרוא את השדות האלה עם טיפוסים, המירו אותו ל-NodeJobOutput. ראו את הסעיף runAndWait() בדף הרצת רכיבים.
לשדה error_hint יש חמישה סוגים. בדקו קודם את kind, ורק אז עברו לשאר השדות:
safety-block: מסנן הבטיחות של המודל עצמו דחה את הפלט. השדהclassהואcopyright,likenessאוsafety. השדהretriedמציין אם Nodaro כבר ניסה שוב פעם אחת, והשדהsuggestedProvider, כשהוא מופיע, מציין מודל שאפשר לנסות עליו שוב את אותה בקשה. הערךsubject: "input_video", כשהוא מופיע, פירושו שהספק דחה את סרטון הקלט של המשימה עצמו: שלחו קליפ אחר. הערךsubject: "input_image"בחסימה מסוגcopyrightפירושו שהספק דחה אחת מתמונות הקלט, כי ייתכן שהיא מוגנת בזכויות יוצרים: שלחו תמונה אחרת. הערךsubject: "prompt"פירושו שהמילים של הספק עצמו ציינו את הפרומפט: שנו את הפרומפט. הערךsubject: "audio"פירושו שהספק האשים את האודיו שנוצר, ולא את התמונה. ראו את הסעיף כשמודל חוסם את הפרומפט בדף יצירת תמונה.policy-block: מדיניות תוכן של הפריסה הזו דחתה את הבקשה או את התוצאה. השדהreasonנכתב בשביל משתמשים, ולכן הציגו אותו כמו שהוא.credits: למשימה נגמרו הקרדיטים באמצע, כי שלב שמשריין קרדיטים משלו נדחה, למשל הסרטון שהרצה של Nodaro Motion או של טרנד מתחילה. השדהcodeהוא הקוד של הדחייה:insufficient_credits, או מגבלה של תוכנית או של סביבת עבודה, כגוןfree_video_limitאוbudget_exceeded. התייחסו לקוד לא מוכר כמו ל-insufficient_credits. הקרדיטים של המשימה מוחזרים. בקשו מהמשתמש לטעון קרדיטים, או להגדיל את המגבלה, ואז הריצו את הבקשה שוב.input-refused: הספק דחה את סרטון הקלט של המשימה בלי לציין סוג של מדיניות תוכן. הערך שלsubjectהוא"input_video". לא מוצע מודל אחר: שלחו קליפ אחר.request-refused: הספק דחה את הבקשה כפי שנשלחה, וציין בה בעיה, כגון הגדרה, הפורמט או הגודל של קובץ, או אורך הפרומפט. אותה בקשה תידחה שוב: שנו את תמונות הקלט, את הסרטון, את הפרומפט או את ההגדרות. עםsubject: "input_video", המילים של הספק ציינו את סרטון הקלט כבעיה, למשל את האורך או הגודל שלו, או שלא נמצאה בו דמות: שלחו קליפ אחר. זו לא חסימה של מדיניות תוכן. בהרצה של Nodaro Motion או של טרנד, זו דחייה של שלב אחד.
jobs.list(params?)
מחזירה את המשימות שלכם, מהחדש לישן, עמוד אחד בכל פעם (GET /v1/jobs).
list(params?: ListJobsParams): Promise<{
data: Job[]
next: string | null
}>מאפיין
סוג
let cursor: string | undefined
do {
const page = await client.jobs.list({ type: "llm-structured", origin: "my-app", cursor })
for (const job of page.data) console.log(job.id, job.status)
cursor = page.next ?? undefined
} while (cursor)כל מסנן משתלב עם האחרים. בעמוד יכולות להיות פחות שורות מ-limit, ואפילו אף שורה, ועדיין יהיה בו next. עברו לעמוד הבא לפי next, ואף פעם לא לפי מספר השורות.
// Your favorited images and videos that came out well
const { data: keepers } = await client.jobs.list({
type: ["generate-image", "generate-video"],
status: "completed",
favorited: true,
rating: "good",
})jobs.rate(id, rating)
מדרגת אחת מהמשימות שלכם כ-"good" או כ-"bad", או מוחקת את הדירוג שלה עם null (PUT /v1/jobs/:id/rating). למשימה יש דירוג אחד, ורק הבעלים שלה יכול לדרג אותה. על משימה של אדם אחר, המתודה זורקת NotFoundError.
rate(id: string, rating: "good" | "bad" | null): Promise<{ data: { jobId: string; rating: "good" | "bad" | null } }>מאפיין
סוג
await client.jobs.rate(jobId, "good")
await client.jobs.rate(jobId, null) // clear itהדירוג מופיע אחר כך ב-Job.rating, ואפשר לסנן לפיו ב-jobs.list(). אפליקציות OAuth צריכות את ההרשאה assets:write. בשרת שאין בו דירוגים, המתודה זורקת NodaroError עם הקוד not_available והסטטוס 503.
jobs.fromUpload(params)
רושמת תמונה שנערכה בדפדפן כמשימה (POST /v1/jobs/from-upload). קודם אחסנו את התמונה הערוכה עם uploads.upload. התוצאה היא משימת image-edit שהסתיימה, פרטית וחינמית, וה-output_data.imageUrl שלה הוא ההעלאה. אחר כך אפשר לדרג אותה, לסמן אותה כמועדפת, לקבל אותה ברשימה עם list({ type: "image-edit" }) ולשמור אותה בסשן, כמו כל משימת תמונה.
fromUpload(params: JobFromUploadParams): Promise<{ data: Job }>מאפיין
סוג
const upload = await client.uploads.upload(editedPng)
const { url: editStateUrl } = await client.uploads.uploadJson(designState)
const { data: job } = await client.jobs.fromUpload({
assetId: upload.assetId!,
sourceJobId,
editStateUrl,
sessionId,
})העלאה אחת היא משימה אחת: שליחה חוזרת של אותו assetId מחזירה את אותה משימה, ולכן ניסיון חוזר אף פעם לא יוצר שתיים. עריכה של תמונה של דמות, אובייקט, יצור או מיקום שומרת את הקשר לנכס הזה. אפליקציות OAuth צריכות את ההרשאה assets:write.
- השגיאה
NotFoundError: ההעלאה, המקור או הסשן לא שלכם. - השגיאה
NodaroErrorעם הקודvalidation_error: ההעלאה היא לא תמונה שאחסנתם, או שלמקור אין תמונה מוגמרת. - השגיאה
JobBlockedError: מדיניות משימות של הפריסה דוחה את התמונה. ראו בדף ה-API רישום תמונה ערוכה.
jobs.getStatus(id)
מחזירה רק את הסטטוס של משימה: id, status, progress, output_data, error_message, error_hint, credit_status ו-completed_at, מתי המשימה הסתיימה לפי השעון של השרת, או null עד שהיא מסתיימת (GET /v1/jobs/:id/status). המתודה משמיטה את נתוני הבקשה ואת שדות העלות, ולכן היא קלה בהרבה מ-get(). השתמשו בה בלולאות תשאול.
getStatus(id: string): Promise<{ data: JobStatusResult }>מאפיין
סוג
async function waitForJob(jobId: string) {
for (;;) {
const { data } = await client.jobs.getStatus(jobId)
if (data.status === "completed") return data.output_data
if (data.status === "failed" || data.status === "cancelled") {
throw new Error(data.error_message ?? data.status)
}
await new Promise((resolve) => setTimeout(resolve, 2_000))
}
}המתודה client.nodes.runAndWait() מריצה את הלולאה הזו בשבילכם, עם דיווח על ההתקדמות, ביטול ושגיאות עם טיפוסים.
jobs.cancel(id)
מבטלת משימה, והקרדיטים ששוריינו לה מוחזרים. אפשר לבטל גם משימה שממתינה לבדיקה.
cancel(id: string): Promise<{ success: true; cancelled: number; inFlight?: boolean }>משימת LLM שמחויבת לפי השימוש ורצה באותו רגע היא החריג. אם הקריאה שלה כבר התחילה, הביטול מחזיר { success: true, cancelled: 0, inFlight: true }: המשימה מסתיימת, ונגבים עליה קרדיטים רק לפי השימוש בפועל. על משימה שנעצרה לפני שהקריאה שלה התחילה מקבלים החזר, חוץ ממה שניסיון קודם של אותה משימה כבר השתמש בו, למשל ניסיון חוזר אחרי ניסיון שחויב.
מאפיין
סוג
const { cancelled } = await client.jobs.cancel(jobId)jobs.delete(id, options?) ו-jobs.restore(id)
המתודה delete מעבירה משימה לפח (DELETE /v1/jobs/:id). מאותו רגע, המשימה לא מופיעה באף קריאה. אפשר לשחזר אותה במשך 30 ימים, ואחר כך היא נמחקת לצמיתות, יחד עם המדיה הפרטית שלה. עותק שנשמר בספרייה נשאר. המתודה restore (POST /v1/jobs/:id/restore) מחזירה את המשימה לכל סשן שהיא הייתה בו. האפשרות { forever: true } מוחקת לצמיתות, כבר עכשיו, משימה שנמצאת בפח. על משימה פעילה, המתודה זורקת NodaroError עם הקוד not_in_trash (סטטוס 409).
רק הבעלים של המשימה יכול למחוק אותה או לשחזר אותה. משימה שעדיין רצה ממשיכה לרוץ, ולכן אם ה-worker שלה צריך להפסיק, בטלו אותה קודם. הקרדיטים לא מוחזרים. אפליקציות OAuth צריכות את ההרשאה assets:write. שתי המתודות מחזירות { success: true }.
delete(id: string, options?: { forever?: boolean }): Promise<{ success: true }>
restore(id: string): Promise<{ success: true }>מאפיין
סוג
await client.jobs.delete(jobId) // to the Trash
await client.jobs.restore(jobId) // undo
await client.jobs.delete(jobId, { forever: true }) // after a delete: gone for goodהמתודה jobs.list() אף פעם לא מחזירה משימה שנמחקה: היא נמצאת ב-client.trash.
client.webhooks
Webhooks יוצאים מודיעים לשרת שלכם כשמשימה מסתיימת, כך שהאפליקציה שלכם לא צריכה לבדוק את הסטטוס. רשמו נקודת קצה ב-HTTPS, ו-Nodaro ישלח אליה בקשת POST על כל אירוע job.completed ו-job.failed בחשבון שלכם. כל קריאה נחתמת עם הסוד של נקודת הקצה עצמה. קריאות שנכשלו נשלחות שוב במרווחים הולכים וגדלים, במשך כ-43 שעות, וכל ניסיון נשמר ביומן המסירות של נקודת הקצה. האירועים, הגוף, הכותרות ולוח הזמנים של הניסיונות החוזרים מפורטים בדף ה-API של Webhooks.
אסימונים של אפליקציות OAuth צריכים את ההרשאה jobs:read. נקודת קצה שאפליקציה מחוברת רושמת מקבלת רק את המשימות שהאפליקציה הזו שלחה בעצמה.
create(input: CreateWebhookEndpointInput): Promise<CreatedWebhookEndpoint> // { data, secret }
list(): Promise<{ data: WebhookEndpoint[] }>
get(id: string): Promise<{ data: WebhookEndpoint }>
update(id: string, input: UpdateWebhookEndpointInput): Promise<{ data: WebhookEndpoint }>
delete(id: string): Promise<{ success: true }>
rotateSecret(id: string, input?: RotateWebhookSecretInput): Promise<RotatedWebhookSecret> // { secret, previousSecretExpiresAt }
deliveries(id: string, params?: ListWebhookDeliveriesParams): Promise<WebhookDeliveryPage>
getDelivery(id: string, deliveryId: string): Promise<{ data: WebhookDelivery }>
test(id: string): Promise<{ data: WebhookDelivery }>webhooks.create(input)
רושמת נקודת קצה ומחזירה אותה עם ה-secret שלה (whsec_…). הסוד מוצג רק פעם אחת, ולכן שמרו אותו עם התצורה של השרת שלכם.
מאפיין
סוג
const { data: endpoint, secret } = await client.webhooks.create({
url: "https://example.com/nodaro-webhook",
events: ["job.completed", "job.failed"],
})
await client.webhooks.test(endpoint.id) // sends a pingלכל כתובת יכולה להיות נקודת קצה אחת (409 url_taken). לחשבון יכולות להיות עד 10 נקודות קצה (400 limit_reached).
webhooks.update(id, input)
משנה כל אחד מהשדות url, events, description (הערך null מוחק אותו) ו-isActive. אחרי 50 מסירות ברצף שנכשלו סופית, Nodaro מכבה את נקודת הקצה ומגדיר את disabledReason לערך "consecutive_failures". הערך isActive: true מפעיל אותה מחדש ומאפס את consecutiveFailures.
webhooks.rotateSecret(id, input?)
יוצרת סוד חדש ומחזירה אותו פעם אחת. מעכשיו הסוד החדש חותם על כל מסירה, כולל ניסיונות חוזרים. הסוד הישן ממשיך לחתום לצידו במשך gracePeriodSeconds, מ-0 עד 604800 (ברירת המחדל: יום אחד), כדי שתוכלו לעדכן את השרת המקבל בלי הפסקה. במהלך הזמן הזה, הכותרת Nodaro-Signature כוללת v1= שני, והפונקציה verifyWebhookSignature מקבלת כל אחד מהם. כדי להפסיק מיד סוד שדלף, העבירו { gracePeriodSeconds: 0 }.
const { secret, previousSecretExpiresAt } = await client.webhooks.rotateSecret(endpoint.id)כשהסוד הישן הפסיק לפעול מיד, השדה previousSecretExpiresAt הוא null.
webhooks.deliveries(id, params?) ו-getDelivery(id, deliveryId)
המתודה deliveries() מחזירה את יומן המסירות, מהחדש לישן. היומן שומר 30 ימים. סננו עם status ("pending", "delivered" או "failed"), ועברו בין העמודים עם limit (מ-1 עד 100, ברירת המחדל 20) ועם cursor. המתודה getDelivery() מחזירה מסירה אחת לפי המזהה שלה.
כל WebhookDelivery כולל event, jobId, status, attempts, responseStatus, responseBody (ה-2 KB הראשונים), durationMs, error, requestBody, nextAttemptAt ו-deliveredAt. השדה requestBody הוא הגוף המדויק שנשלח, והוא הופך ל-null ברגע שהמסירה מצליחה.
webhooks.test(id)
מכניסה ping לתור ומחזירה את המסירה שלו. ה-ping נשלח בתוך שניות, בניסיון אחד, גם לנקודת קצה כבויה. בדקו את המצב שלו עם getDelivery(id, delivery.id).
verifyWebhookSignature(options)
בודקת קריאה שנקודת הקצה שלכם קיבלה, ומחזירה את האירוע אחרי פענוח. זו פונקציה שמיוצאת ברמה העליונה של @nodaro/sdk, ולא מתודה של client. היא משתמשת רק ב-Web Crypto, ולכן היא רצה ב-Node 20 ומעלה, ב-Deno, ב-Bun, ב-Cloudflare Workers, ב-Vercel Edge ובדפדפנים.
verifyWebhookSignature(options: {
payload: string | Uint8Array | ArrayBuffer // the raw body, as received
header: string | readonly string[] | null | undefined // Nodaro-Signature
secret: string // whsec_…
toleranceSeconds?: number // default 300; 0 turns the check off
}): Promise<WebhookEvent>העבירו את הגוף הגולמי בדיוק כפי שהתקבל, ואף פעם לא JSON שפענחתם ועשיתם לו סריאליזציה מחדש. האירוע הוא JobWebhookEvent, שה-data.job שלו הוא Job, או PingWebhookEvent. כשהבדיקה נכשלת, הפונקציה זורקת WebhookSignatureError עם אחד מהקודים האלה: missing_header, malformed_header, signature_mismatch, timestamp_outside_tolerance, invalid_payload, missing_secret או crypto_unavailable. ההשוואה נעשית בזמן קבוע.
import { verifyWebhookSignature, WebhookSignatureError } from "@nodaro/sdk"
export async function POST(request: Request) {
try {
const event = await verifyWebhookSignature({
payload: await request.text(),
header: request.headers.get("nodaro-signature"),
secret: process.env.NODARO_WEBHOOK_SECRET!,
})
if (event.type === "job.completed") await saveResult(event.data.job)
return new Response(null, { status: 204 })
} catch (err) {
if (err instanceof WebhookSignatureError) return new Response(err.code, { status: 400 })
throw err
}
}כשהשרת שלכם עונה בסטטוס 2xx כלשהו בתוך 10 שניות, המסירה נחשבת למסירה שהצליחה. השדה id שבגוף הוא מזהה המסירה, והוא נשאר זהה בכל ניסיון חוזר, ולכן השתמשו בו כדי לדלג על אירוע שכבר טיפלתם בו.
client.videoPro
שליטה בהרצות של רכיב יצירת וידאו Pro, הרכיב שמרנדר סרטונים ארוכים במקטעים. המשאב עובד ב-Nodaro Cloud. התחילו את ההרצה כמו כל הרצה של רכיב, ואז השתמשו במתודות האלה על המשימה שלה.
videoPro.stop(jobId)
עוצרת בצורה מסודרת משימה פעילה של רכיב יצירת וידאו Pro. המקטע שנוצר באותו רגע ננטש, אבל משלמים עליו בכל זאת, והמקטעים שנותרו לא נוצרים. המקטעים שהסתיימו מתאחדים לסרטון הסופי של המשימה, והקרדיטים המשוריינים שלא נדרשו מוחזרים. משימה שעוד לא התחילה מבוטלת, עם החזר מלא.
stop(jobId: string): Promise<StopVideoProResult>מאפיין
סוג
await client.videoPro.stop(jobId)
const { data } = await client.jobs.getStatus(jobId) // becomes completed, with the partial videoהמשיכו לבדוק את הסטטוס של המשימה מדי כמה שניות. היא מסתיימת עם output_data.pro.stopped בערך true.
videoPro.continueRun(jobId, opts?)
ממשיכה הרצה שנעצרה, נכשלה או הסתיימה, כמשימה חדשה. המקטעים שלפני fromSegment משמשים שוב, וכל מקטע ממנו והלאה נוצר מחדש. משלמים רק על המקטעים שנוצרים מחדש, ועוד התשלום הקבוע של Pro.
continueRun(jobId: string, opts?: { fromSegment?: number }): Promise<ContinueVideoProResult>מאפיין
סוג
const { jobId: newJobId, fromSegment } = await client.videoPro.continueRun(jobId, { fromSegment: 4 })התוצאה כוללת את ה-jobId החדש, שאת הסטטוס שלו צריך לבדוק, ויכולה לכלול גם continuedFromJobId, fromSegment, segmentCount ו-deduped.
שאלות נפוצות
מה ההבדל בין משימה לרשומת הרצה?
משימה היא יצירה אחת, כגון תמונה אחת או סרטון אחד. רשומת הרצה מייצגת הרצה אחת של תהליך שלם, והיא מקבצת משימה אחת לכל רכיב AI, יחד עם המצב של כל רכיב.
לאיזו מתודה כדאי לקרוא בלולאת תשאול?
ל-client.jobs.getStatus(jobId). המתודה מחזירה רק את הסטטוס, ההתקדמות, הפלט והשגיאה, ולכן היא קלה בהרבה מ-client.jobs.get.
האם ביטול משימה מחזיר את הקרדיטים שלה?
כן. המתודה client.jobs.cancel עוצרת את המשימה, והקרדיטים ששוריינו לה מוחזרים. ביטול מיידי של הרצת תהליך עושה אותו דבר למשימות שרצות בה. החריג הוא משימת LLM שמחויבת לפי השימוש, שהקריאה שלה כבר התחילה: עליה נגבים קרדיטים לפי השימוש בפועל.
האם Nodaro יכול להודיע לשרת כשמשימה מסתיימת, במקום שהאפליקציה תבדוק את הסטטוס?
כן. רשמו נקודת קצה ב-HTTPS עם client.webhooks.create. מאותו רגע, Nodaro שולח בקשת POST חתומה על כל אירוע job.completed ו-job.failed בחשבון שלכם. בדקו כל קריאה עם verifyWebhookSignature.
מה המשמעות של הסטטוס pending_review?
הסטטוס pending_review פירושו שמדיניות תוכן של הפריסה הזו מעכבת את התוצאה עד שאדם יבדוק אותה. זה לא סטטוס סופי: בהמשך המשימה מסתיימת בסטטוס completed, failed או cancelled. המשיכו לחכות, ואל תריצו את הבקשה שוב.
דפים קשורים
הרצת רכיבים
תהליכים ופרויקטים
שגיאות
משימות
ה-API של Webhooks
עודכן לאחרונה