# SDK ל-TypeScript

> התקנה של ‎@nodaro/sdk, אימות עם אסימון API והרצה של רכיבים ותהליכים של Nodaro מ-TypeScript, ב-Node.js, בדפדפן ובסביבות ריצה בקצה.

Source: https://nodaro.ai/he/docs/developers/sdk

**ה-SDK של Nodaro ל-TypeScript**, שמפורסם ב-npm בשם `@nodaro/sdk`, הוא הלקוח עם הטיפוסים ל-REST API של Nodaro. ה-SDK מריץ רכיבים בודדים ותהליכים שלמים, ממתין לתוצאות שלהם ומנהל דמויות, קולות, מדיה ועוד. ה-SDK עובד ב-Node.js, בדפדפן ובסביבות ריצה בקצה, וכל שגיאה של ה-API מגיעה כמחלקת שגיאה ייעודית שאפשר לתפוס.

## התקנה
```bash
npm install @nodaro/sdk
```

- החבילה היא קוד פתוח, ברישיון Apache-2.0. ראו את [`@nodaro/sdk` ב-npm](https://www.npmjs.com/package/@nodaro/sdk) ואת [קוד המקור שלה ב-GitHub](https://github.com/nodaroai/app.nodaro.ai/tree/main/packages/client).
- החבילה כוללת בנייה כ-ES module וכ-CommonJS, עם הגדרות טיפוסים של TypeScript.
- החבילה דורשת Node.js 20 ומעלה. היא רצה גם בכל סביבת ריצה עם `fetch` ו-`URL` גלובליים: דפדפנים מודרניים, React Native, Cloudflare Workers, Deno ו-Bun.
- החבילה מתקינה איתה עוד שתי חבילות של Nodaro: `@nodaro/shared`, עם הטיפוסים של הנתונים שעוברים ב-API ועם קטלוג המודלים, ו-`@nodaro/prompts`, עם פונקציות העזר לפרומפטים.
- החבילות `@supabase/supabase-js` ו-`@supabase/ssr` הן תלויות peer אופציונליות. התקינו אותן רק לאפליקציית דפדפן שהמשתמשים שלה מתחברים עם Supabase, דרך `supabaseAuth` או `@nodaro/sdk/supabase`.
- [ה-CLI של Nodaro](https://nodaro.ai/docs/developers/cli) בנוי על ה-SDK הזה, ולכן פקודת CLI וקריאה ל-SDK מגיעות לאותן נקודות קצה.

## קבלת אסימון API
### יצירת האסימון
התחברו ל-[Nodaro](https://app.nodaro.ai), פתחו את הדף **הגדרות › מפתחות API** ולחצו על **יצירת אסימון**.

### העתקת האסימון כשהוא מוצג
האסימון מתחיל ב-`ndr_` ומוצג רק פעם אחת. Nodaro שומר רק גיבוב שלו, ולכן אי אפשר להציג שוב אסימון שאבד. במקום זאת, צרו אסימון חדש.

### שמירת האסימון מחוץ לקוד
שמרו את האסימון במשתנה סביבה, כגון `NODARO_TOKEN`, או במאגר הסודות שלכם. אף פעם אל תכניסו אותו לקוד שרץ בצד הלקוח.

אסימון אישי פועל בשמכם. כדי לפעול בשם אנשים אחרים, למשל באפליקציה שמשתמשים רבים מתחברים אליה, השתמשו במקום זאת ב-[OAuth](https://nodaro.ai/docs/developers/oauth). הדף [אימות](https://nodaro.ai/docs/developers/sdk/auth) משווה בין כל האפשרויות.

## הקריאה הראשונה שלכם
```ts

const client = createClient({
baseUrl: "https://app.nodaro.ai",
auth: new StaticTokenAuth(process.env.NODARO_TOKEN!),
})

const { data: nodes } = await client.nodes.list()
console.log(`${nodes.length} node types available`)
```

המתודה `client.nodes.list()` לא עולה כלום ולא דורשת הרשאות, ולכן היא בדיקה ראשונה טובה של החיבור. בהתקנה באירוח עצמי, הגדירו את `baseUrl` לכתובת של המופע שלכם. באפליקציית דפדפן שמוגשת מאותו origin כמו Nodaro, השתמשו במחרוזת ריקה. הדף [לקוח](https://nodaro.ai/docs/developers/sdk/client) מפרט את כל האפשרויות של `createClient`.

## יצירת תמונה, ואחריה סרטון
```ts
const image = await client.nodes.runAndWait("generate-image", {
prompt: "A snow leopard resting on a rock at sunrise",
provider: "nano-banana-2",
})
console.log(image.imageUrl)

const video = await client.nodes.runAndWait("generate-video", {
prompt: "The snow leopard slowly turns its head toward the camera",
imageUrl: image.imageUrl,
provider: "seedance-2-fast",
duration: 4,
})
console.log(video.videoUrl)
```

המתודה `runAndWait` מתחילה את ההרצה, בודקת את הסטטוס שלה ומחזירה את הפלט של המשימה: השדה `imageUrl` בתמונות, `videoUrl` בווידאו ו-`audioUrl` באודיו. הקריאה הראשונה מריצה את רכיב [יצירת תמונה](https://nodaro.ai/docs/nodes/image/generate-image) עם המודל [Nano Banana 2](https://nodaro.ai/docs/models/image/nano-banana-2). הקריאה השנייה מנפישה את התמונה הזו עם רכיב [יצירת וידאו](https://nodaro.ai/docs/nodes/video/generate-video) והמודל [Seedance 2 Fast](https://nodaro.ai/docs/models/video/seedance-2-fast).

השמיטו את `provider` כדי להשתמש במודל ברירת המחדל של הרכיב. בדף של כל רכיב מפורטים המודלים שהוא יכול להריץ והמחירים שלהם בקרדיטים, והמתודה `client.models.list()` מחזירה את אותו קטלוג מתוך הקוד. ראו את הדף [מודלים וקרדיטים](https://nodaro.ai/docs/developers/sdk/models-and-credits).

## איך הרצות עובדות
היצירה היא אסינכרונית. בקשה מתחילה **משימה** ב-worker וחוזרת מיד. התוצאה מגיעה אחרי כמה שניות או כמה דקות.

| קריאה | מה חוזר | מה עושים אחר כך |
| --- | --- | --- |
| `client.nodes.run(type, params)` | `{ jobId }` | בודקים את הסטטוס עם `client.jobs.getStatus(jobId)` מדי כמה שניות, עד שהוא `completed`, `failed` או `cancelled`. |
| `client.nodes.runAndWait(type, params, opts)` | הפלט של המשימה | לא צריך לעשות כלום. ה-SDK בודק את הסטטוס כל 2 שניות, עד 15 דקות. |
| `client.nodes.runMany(type, paramsList, opts)` | `{ jobId, output }` אחד לכל בקשה | לא צריך לעשות כלום. ההרצות מתחילות יחד, והתוצאות חוזרות לפי סדר הבקשות. |
| `client.workflows.run(id)` | `{ executionId, status }` | בודקים את הסטטוס עם `client.executions.get(executionId)` מדי כמה שניות, עד שההרצה מסתיימת. |

כמה סוגי רכיבים, כגון [שילוב טקסט](https://nodaro.ai/docs/nodes/automate/combine-text), רצים בתוך הבקשה עצמה ומחזירים את התוצאה ישירות, בלי `jobId`. הדף [הרצת רכיבים](https://nodaro.ai/docs/developers/sdk/nodes) מסביר כל מתודת הרצה, והדף [משימות והרצות](https://nodaro.ai/docs/developers/sdk/jobs-and-executions) מסביר את הסטטוסים.

### הצגת ההתקדמות ואפשרות למשתמש להפסיק לחכות
```ts

const controller = new AbortController()
stopButton.onclick = () => controller.abort()

try {
const clip = await client.nodes.runAndWait(
"generate-video",
{ prompt: "Waves roll onto a black sand beach", provider: "seedance-2-fast", duration: 4 },
{
signal: controller.signal,
onProgress: (status) => setProgressBar(status.progress ?? 0),
},
)
showVideo(clip.videoUrl)
} catch (err) {
if (err instanceof JobAbortedError && err.jobId) {
await client.jobs.cancel(err.jobId)
} else {
throw err
}
}
```

הפונקציה `onProgress` מקבלת את הסטטוס של המשימה בכל בדיקה, עם `progress` מ-0 עד 100 כשהמודל מדווח על התקדמות. ביטול דרך ה-signal עוצר רק את ההמתנה. המשימה ממשיכה לרוץ עד שתבטלו אותה עם `client.jobs.cancel(jobId)`, ואז גם הקרדיטים ששוריינו לה מוחזרים.

הציגו כל תוצאה ברגע שהיא מגיעה. ביצירה של שני שלבים, הציגו את התמונה בזמן ששלב הווידאו עדיין רץ.

## בחירת דרך האימות
| ספק האימות | מתי להשתמש בו | מקור האסימון |
| --- | --- | --- |
| `StaticTokenAuth` | קוד בשרת עם אסימון קבוע אחד | אסימון API (`ndr_...`) או אסימון גישה של OAuth (`ndr_app_...`) |
| `CallbackAuth` | כשאתם מרעננים או מחליפים אסימונים בעצמכם | הפונקציה שלכם, שנקראת לפני כל בקשה |
| `supabaseAuth` | אפליקציית דפדפן שהמשתמשים שלה מתחברים לאותו מופע Nodaro | הסשן הפעיל של המשתמש |

לפני כל בקשה, ה-SDK מבקש אסימון מספק האימות ושולח אותו כ-`Authorization: Bearer <token>`. כשהספק מחזיר `null`, הבקשה נשלחת בלי הכותרת. הפרטים על כל ספק אימות ועל הכללים המיוחדים לדפדפן מופיעים בדף [אימות](https://nodaro.ai/docs/developers/sdk/auth).

## טיפול בשגיאות
כשה-API עונה בשגיאה, כל מתודה זורקת תת־מחלקה ייעודית של `NodaroError`. תפסו קודם את המחלקות הספציפיות, ואת `NodaroError` בסוף.

```ts

InsufficientCreditsError,
NodaroError,
RateLimitedError,
UnauthorizedError,
} from "@nodaro/sdk"

try {
await client.workflows.run(workflowId)
} catch (err) {
if (err instanceof InsufficientCreditsError) {
showPaywall({ required: err.required, available: err.available })
} else if (err instanceof UnauthorizedError) {
askForANewToken()
} else if (err instanceof RateLimitedError) {
retryLater()
} else if (err instanceof NodaroError) {
console.error(`API error ${err.status} (${err.code}): ${err.message}`)
} else {
throw err // a network failure, not an API answer
}
}
```

לכל `NodaroError` יש `message`, `status` עם סטטוס ה-HTTP ו-`code` קבוע, כגון `insufficient_credits`. הדף [שגיאות](https://nodaro.ai/docs/developers/sdk/errors) מפרט כל מחלקה ומתי היא נזרקת.

## שימושים נפוצים
### הרצת תהליך והמתנה לסיום שלו
המתודה `client.workflows.run()` יוצרת **רשומת הרצה**, כלומר מתחילה הרצה אחת של כל הרכיבים בתהליך, וחוזרת מיד. בדקו את הסטטוס עם `client.executions.get()` מדי כמה שניות, עד שהוא סופי.

```ts
const { executionId } = await client.workflows.run(workflowId)

for (;;) {
const { data } = await client.executions.get(executionId)
console.log(`${data.completedNodes}/${data.totalNodes} nodes done`)

if (["completed", "failed", "cancelled", "timed_out"].includes(data.status)) {
if (data.status !== "completed") throw new Error(data.errorMessage ?? data.status)
console.log(`Done. Used ${data.totalCreditsUsed} credits.`)
break
}
await new Promise((resolve) => setTimeout(resolve, 2_000))
}
```

כדי להריץ רק חלק מהרכיבים, העבירו `{ nodeIds: [...] }` כארגומנט השני. ראו את הדף [תהליכים ופרויקטים](https://nodaro.ai/docs/developers/sdk/workflows).

### יצירת כמה תוצאות לבחירה בבת אחת
```ts
const results = await client.nodes.runMany("generate-image", [
{ prompt: "A lighthouse at dawn, watercolor" },
{ prompt: "A lighthouse at dusk, watercolor" },
{ prompt: "A lighthouse in a storm, watercolor" },
])
for (const { jobId, output } of results) console.log(jobId, output.imageUrl)
```

המתודה `runMany` נכשלת כולה אם הרצה אחת כלשהי נכשלת. כדי שמודל יבחר את התוצאה הטובה ביותר, העבירו את הכתובות ל-[`client.reduce.run()`](https://nodaro.ai/docs/developers/sdk/llm-and-reduce).

כשמדובר בתמונות, קריאה אחת יכולה לעשות את אותו הדבר. המתודה [`runBatchAndWait()`](https://nodaro.ai/docs/developers/sdk/nodes#runbatchandwaittype-params-opts) מקבלת `count` (מ-1 עד 4 תמונות) או `models` (מ-2 עד 4 מודלי תמונה). האצווה מחויבת כיחידה אחת, ותמונה אחת שנכשלת אף פעם לא מבטלת את שאר התמונות.

```ts
const { results } = await client.nodes.runBatchAndWait("generate-image", {
prompt: "A lighthouse at dusk, watercolor",
count: 4,
})
for (const r of results) if (r.status === "completed") console.log(r.output.imageUrl)
```

### העלאת קובץ ושימוש בו
```ts
const upload = await client.uploads.upload(file) // a File, in the browser or Node.js
const portrait = await client.nodes.runAndWait("generate-image", {
prompt: "The same person as a watercolor portrait",
referenceImageUrls: [upload.url],
})
```

ההעלאה מחזירה `url` ציבורי, שאפשר להעביר לכל רכיב שמקבל כתובת של תמונה, של סרטון או של אודיו. ראו את הדף [מדיה והעלאות](https://nodaro.ai/docs/developers/sdk/media-and-uploads).

### בדיקת המחיר לפני ההרצה
```ts
const { total } = await client.credits.balance()
const { data: prices } = await client.credits.modelCosts(["nano-banana-pro", "nano-banana-pro:4K"])

if (total < prices["nano-banana-pro:4K"]) showPaywall()
```

מחירים ויתרות קיימים ב-Nodaro Cloud. ראו את הדפים [מודלים וקרדיטים](https://nodaro.ai/docs/developers/sdk/models-and-credits) ו[קרדיטים](https://nodaro.ai/docs/concepts/credits).

### הודעה כשמשימה מסתיימת, במקום תשאול
רשמו נקודת קצה ב-HTTPS פעם אחת. מאותו רגע, Nodaro שולח אליה בקשת POST חתומה על כל אירוע `job.completed` ו-`job.failed` בחשבון שלכם, ומנסה שוב עד שהשרת שלכם עונה בסטטוס 2xx.

```ts
const { data: endpoint, secret } = await client.webhooks.create({ url: "https://example.com/nodaro-webhook" })
// `secret` is shown only once: keep it with your server's configuration.
await client.webhooks.test(endpoint.id) // a ping; see client.webhooks.deliveries(endpoint.id)
```

בצד המקבל, בדקו את החתימה על הגוף הגולמי לפני שאתם סומכים עליו:

```ts

const event = await verifyWebhookSignature({
payload: rawBody,
header: request.headers.get("nodaro-signature"),
secret: process.env.NODARO_WEBHOOK_SECRET!,
})
if (event.type === "job.completed") console.info(event.data.job.output_data)
```

האירועים, הגוף ולוח הזמנים של הניסיונות החוזרים מפורטים בסעיף [`client.webhooks`](https://nodaro.ai/docs/developers/sdk/jobs-and-executions#clientwebhooks) בדף משימות והרצות ובדף [ה-API של Webhooks](https://nodaro.ai/docs/developers/api/webhooks).

### שיפור פרומפט לפני היצירה
```ts
const { prompt } = await client.promptHelper.enhance({
nodeType: "generate-image",
prompt: "snow leopard on a rock",
})
```

[אשף הפרומפטים](https://nodaro.ai/docs/developers/sdk/pickers-and-prompts) משכתב רעיון גולמי לפרומפט מפורט, בשביל הרכיב שאתם מציינים. כל קריאה עולה קרדיטים.

## שימוש ב-SDK עם עוזר AI לכתיבת קוד
- **התוסף ל-Claude Code.** הריצו את `/plugin marketplace add nodaroai/app.nodaro.ai`, ואחר כך את `/plugin install nodaro`. התוסף מוסיף סקיל שמכיר את הדפוסים של ה-SDK, את המודלים ואת הקרדיטים, ומחבר את שרת ה-MCP ש-Nodaro מארח. ראו את הדף [סקילים לסוכנים](https://nodaro.ai/docs/developers/agent-skills).
- **עוזרים אחרים.** קובץ ה-README של החבילה ב-npm מתחיל במבוא קצר שנכתב לעוזרי קוד. הדביקו אותו ב-Cursor או בכל עוזר אחר, יחד עם הבקשה שלכם.
- **בלי קוד בכלל.** כדי שעוזר AI יעבוד עם Nodaro בשבילכם, חברו אותו דרך [MCP](https://nodaro.ai/docs/mcp).

## מדריך
<Card title="לקוח" href="/docs/developers/sdk/client" description="createClient, כל האפשרויות, סביבות עבודה והרשימה המלאה של המשאבים." />
<Card title="אימות" href="/docs/developers/sdk/auth" description="StaticTokenAuth, CallbackAuth, supabaseAuth וסשנים משותפים בדפדפן." />
<Card title="שגיאות" href="/docs/developers/sdk/errors" description="כל מחלקות השגיאה, עם הסטטוס והקוד של כל אחת, ואיך להתאושש." />
<Card title="הרצת רכיבים" href="/docs/developers/sdk/nodes" description="run, runAndWait ו-runMany, עם טיפוסים לכל הפרמטרים." />
<Card title="תהליכים ופרויקטים" href="/docs/developers/sdk/workflows" description="יצירה, עדכון, שיתוף, ייצוא והרצה של תהליכים." />
<Card title="משימות והרצות" href="/docs/developers/sdk/jobs-and-executions" description="תשאול, רשימה, ביטול ומחיקה של הרצות." />

ה-SDK עוטף את אותן נקודות קצה כמו [ה-REST API](https://nodaro.ai/docs/developers/api). לנקודת קצה שעדיין אין לה מתודה ב-SDK, קראו לה עם `client.request()`, ששומרת על אותו אימות ועל אותן שגיאות עם טיפוסים.

## שאלות נפוצות

### מהו ‎@nodaro/sdk?

החבילה ‎@nodaro/sdk היא הלקוח הרשמי ל-TypeScript של ה-REST API של Nodaro. ה-SDK מריץ רכיבים ותהליכים, ממתין לתוצאות שלהם ומנהל דמויות, קולות, מדיה ועוד, ולכל קריאה יש מתודה עם טיפוסים ושגיאה עם טיפוסים.

### איך מגדירים אימות ב-SDK של Nodaro?

צרו אסימון ב-Nodaro, בדף הגדרות › מפתחות API, שמרו אותו במשתנה סביבה והעבירו אותו ל-createClient כ-new StaticTokenAuth(token)‎. אפליקציות דפדפן ואפליקציות OAuth משתמשות במקום זאת ב-supabaseAuth או ב-CallbackAuth.

### באילו סביבות ריצה ה-SDK תומך?

ה-SDK של Nodaro תומך ב-Node.js 20 ומעלה, ובכל סביבת ריצה עם fetch ו-URL גלובליים, כגון דפדפנים מודרניים, React Native, Cloudflare Workers, Deno ו-Bun.

### האם צריך לבדוק ידנית אם התוצאות מוכנות?

לא. המתודה client.nodes.runAndWait מתחילה הרצה, בודקת את הסטטוס של המשימה שלה כל 2 שניות ומחזירה את כתובות הפלט. כתבו לולאה משלכם עם client.jobs.getStatus רק כשאתם צריכים שליטה מלאה.

### האם אפשר להשתמש ב-SDK עם התקנה של Nodaro באירוח עצמי?

כן. הגדירו את baseUrl לכתובת של המופע שלכם. חלק מהמשאבים, כגון הפקות Studio, Recast וארגונים, קיימים רק ב-Nodaro Cloud ומחזירים 404 בכל מקום אחר.
