דילוג לתוכן
תיעוד Nodaro
תיעודמדריך הרכיביםמודליםתבניותסוכני AI (MCP)מפתחיםאירוח עצמימחקרהשוואות
SDK ל-TypeScript

משימות והרצות

תשאול, רשימה, דירוג, ביטול ומחיקה של הרצות 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. המשיכו לחכות, ואל תריצו את הבקשה שוב.

עודכן לאחרונה

בדף הזה