# לקוח

> יצירת לקוח של ה-SDK של Nodaro עם createClient: כתובת הבסיס, האימות, פסק הזמן וסביבת העבודה, וכל המשאבים שהלקוח חושף.

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

**הלקוח** הוא האובייקט ש-`createClient()` מחזירה: מופע של `NodaroClient` ששומר את כתובת הבסיס, את ספק האימות ואת ההגדרות שלכם, וחושף כל חלק של ה-API של Nodaro כמשאב, כמו `client.workflows` או `client.nodes`. יוצרים אותו פעם אחת ומשתמשים בו שוב בכל קריאה.

## יצירת לקוח
```ts

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

```ts
createClient(options: ClientOptions): NodaroClient
```

<TypeTable
type={{
baseUrl: {
type: 'string',
required: true,
description: "שרת Nodaro, למשל https://app.nodaro.ai או הכתובת של ההתקנה שלכם באירוח עצמי. באפליקציית דפדפן, השתמשו במחרוזת ריקה לבקשות מאותו origin. לוכסן בסוף הכתובת נמחק.",
},
auth: {
type: 'Auth',
required: true,
description: "ספק האימות: new StaticTokenAuth(token)‎, supabaseAuth(supabase)‎, new CallbackAuth(fn)‎ או כל אובייקט עם מתודה getToken()‎.",
typeDescriptionLink: '/docs/developers/sdk/auth',
},
fetch: {
type: 'typeof fetch',
default: 'globalThis.fetch',
description: "פונקציית fetch משלכם, לבדיקות, לניסיונות חוזרים או למעקב אחרי בקשות.",
},
timeoutMs: {
type: 'number',
default: '60000',
description: "פסק הזמן של כל בקשה, באלפיות שנייה. כשהזמן נגמר, הבקשה מבוטלת.",
},
workspaceId: {
type: 'string',
description: "מזהה סביבת העבודה שבה כל בקשה פועלת, שנשלח בכותרת X-Nodaro-Workspace. השמיטו אותו כדי לעבוד במרחב האישי שלכם. לארגונים ב-Nodaro Cloud בלבד.",
},
clientLabel: {
type: 'string',
default: "'sdk/<version>'",
description: "הערך של הכותרת X-Nodaro-Client. Nodaro רושם אותו כמקור של כל משימה. הגדירו אותו רק כשאתם בונים כלי אחר מעל ה-SDK.",
},
}}
/>

ה-SDK מייצא את `NodaroClient` גם כמחלקה, כך שאפשר להגדיר טיפוס לפונקציה שמקבלת לקוח:

```ts

async function countWorkflows(client: NodaroClient, projectId: string) {
const { data } = await client.workflows.list({ projectId })
return data.length
}
```

## המשאבים של הלקוח
הפונקציה `createClient` יוצרת את כל המשאבים, וניגשים לכל משאב דרך `client.<resource>`.

| משאב | מה הוא מכסה | קריאה נוספת |
| --- | --- | --- |
| `client.workflows` | תהליכים: יצירה, עדכון, שיתוף, ייצוא, ייבוא והרצה | [תהליכים ופרויקטים](https://nodaro.ai/docs/developers/sdk/workflows) |
| `client.projects` | הפרויקטים שבהם נמצאים התהליכים | [תהליכים ופרויקטים](https://nodaro.ai/docs/developers/sdk/workflows) |
| `client.sessions` | סשנים של יצירה בתוך פרויקטים | [תהליכים ופרויקטים](https://nodaro.ai/docs/developers/sdk/workflows#clientsessions) |
| `client.executions` | הרצות של תהליך שלם | [משימות והרצות](https://nodaro.ai/docs/developers/sdk/jobs-and-executions) |
| `client.jobs` | משימות יצירה בודדות, עם דירוגים ומסננים | [משימות והרצות](https://nodaro.ai/docs/developers/sdk/jobs-and-executions) |
| `client.webhooks` | נקודות קצה ש-Nodaro קורא להן כשמשימה מסתיימת | [משימות והרצות](https://nodaro.ai/docs/developers/sdk/jobs-and-executions#clientwebhooks) |
| `client.videoPro` | עצירה של הרצה ברכיב יצירת וידאו Pro, או הרצת המשך שלה | [משימות והרצות](https://nodaro.ai/docs/developers/sdk/jobs-and-executions) |
| `client.nodes` | קטלוג הרכיבים והרצות של רכיב יחיד | [הרצת רכיבים](https://nodaro.ai/docs/developers/sdk/nodes) |
| `client.apps` | אפליקציות שפורסמו וההרצות שלהן | [אפליקציות ותבניות](https://nodaro.ai/docs/developers/sdk/apps-and-templates) |
| `client.templates` | שוק התבניות | [אפליקציות ותבניות](https://nodaro.ai/docs/developers/sdk/apps-and-templates) |
| `client.tutorials` | מדריכי וידאו ומדריכי תהליכים | [אפליקציות ותבניות](https://nodaro.ai/docs/developers/sdk/apps-and-templates) |
| `client.llm` | פלט מובנה ממודל שפה | [LLM ובחירת המיטב](https://nodaro.ai/docs/developers/sdk/llm-and-reduce) |
| `client.reduce` | בחירה של התוצאה הטובה ביותר מתוך תוצאות רבות, או איחוד שלהן | [LLM ובחירת המיטב](https://nodaro.ai/docs/developers/sdk/llm-and-reduce) |
| `client.uploads` | העלאת קבצים | [מדיה והעלאות](https://nodaro.ai/docs/developers/sdk/media-and-uploads) |
| `client.library` | המדיה ששמרתם | [מדיה והעלאות](https://nodaro.ai/docs/developers/sdk/media-and-uploads) |
| `client.gallery` | הגלריה הציבורית והמועדפים שלכם | [מדיה והעלאות](https://nodaro.ai/docs/developers/sdk/media-and-uploads#clientgallery) |
| `client.media` | הורדה, קיצוץ, הוספת כתוביות, הוספת שכבות וקולאז׳ של מדיה | [מדיה והעלאות](https://nodaro.ai/docs/developers/sdk/media-and-uploads) |
| `client.voices` | קולות, החלפת קול, עיצוב קול ודיבוב | [קולות ואודיו](https://nodaro.ai/docs/developers/sdk/voices-and-audio) |
| `client.audio` | הפרדה, בידוד, מיקס, קיצוץ ותמלול של אודיו | [קולות ואודיו](https://nodaro.ai/docs/developers/sdk/voices-and-audio) |
| `client.edit` | זיהוי שקט, סנכרון אודיו, תוכניות עריכה ורינדור של EDL | [עריכה](https://nodaro.ai/docs/developers/sdk/editing) |
| `client.scene3d` | סצנות תלת־ממד שאפשר לערוך, ורינדור תלת־ממד Pro | [סצנות תלת־ממד](https://nodaro.ai/docs/developers/sdk/scenes-3d) |
| `client.characters` | דמויות | [דמויות](https://nodaro.ai/docs/developers/sdk/characters) |
| `client.locations` | מיקומים | [מיקומים](https://nodaro.ai/docs/developers/sdk/locations) |
| `client.objects` | אובייקטים ואביזרים | [אובייקטים ויצורים](https://nodaro.ai/docs/developers/sdk/objects-and-creatures) |
| `client.creatures` | חיות ויצורים | [אובייקטים ויצורים](https://nodaro.ai/docs/developers/sdk/objects-and-creatures) |
| `client.community` | ספריית הנכסים המשותפת של הקהילה | [ספריית הקהילה](https://nodaro.ai/docs/developers/sdk/community) |
| `client.studio` | הפקות Studio | [הפקות Studio](https://nodaro.ai/docs/developers/sdk/studio) |
| `client.shots` | רשומות השוטים המשותפות שמאחורי קישורי שיתוף | [הפקות Studio](https://nodaro.ai/docs/developers/sdk/studio) |
| `client.recast` | הרצות של Recast ותסריטים שכתבתם | [Recast ב-SDK](https://nodaro.ai/docs/developers/sdk/recast) |
| `client.castSwap` | החלפת האנשים, חיות המחמד, המוצרים או המיקום בסרטון קצר, ב-Nodaro Cloud בלבד | [ה-API של Nodaro Motion](https://nodaro.ai/docs/developers/api/cast-swap#from-the-sdk) |
| `client.trends` | מתכונים מוכנים של Nodaro Motion שרצים עם התמונות שלכם, ב-Nodaro Cloud בלבד | [טרנדים](https://nodaro.ai/docs/developers/api/trends#from-the-sdk) |
| `client.pipelines` | פייפליינים של **סיפור ← וידאו** | [פייפליינים](https://nodaro.ai/docs/developers/sdk/pipelines) |
| `client.copilot` | שיחות עם ה-Copilot, רק בתוך האפליקציה של Nodaro | [Copilot ב-SDK](https://nodaro.ai/docs/developers/sdk/copilot) |
| `client.models` | קטלוג המודלים | [מודלים וקרדיטים](https://nodaro.ai/docs/developers/sdk/models-and-credits) |
| `client.credits` | היתרה שלכם והמחירים של המודלים | [מודלים וקרדיטים](https://nodaro.ai/docs/developers/sdk/models-and-credits) |
| `client.billing` | תוכניות, מחירים והמנוי שלכם | [מודלים וקרדיטים](https://nodaro.ai/docs/developers/sdk/models-and-credits#clientbilling) |
| `client.pickerCatalogs` | האפשרויות התקפות של כל בורר | [בוררים, ערכות ופרומפטים](https://nodaro.ai/docs/developers/sdk/pickers-and-prompts) |
| `client.catalogs` | כל קטלוגי הבוררים בקריאה אחת | [בוררים, ערכות ופרומפטים](https://nodaro.ai/docs/developers/sdk/pickers-and-prompts) |
| `client.presets` | ערכות שמורות וערכות מובנות של רכיבים | [בוררים, ערכות ופרומפטים](https://nodaro.ai/docs/developers/sdk/pickers-and-prompts) |
| `client.palettes` | פלטות הצבעים שלכם | [בוררים, ערכות ופרומפטים](https://nodaro.ai/docs/developers/sdk/pickers-and-prompts#clientpalettes) |
| `client.moodboards` | המודבורדים שלכם | [בוררים, ערכות ופרומפטים](https://nodaro.ai/docs/developers/sdk/pickers-and-prompts#clientmoodboards) |
| `client.promptHelper` | אשף הפרומפטים | [בוררים, ערכות ופרומפטים](https://nodaro.ai/docs/developers/sdk/pickers-and-prompts) |
| `client.organizations` | ארגונים, חברים והזמנות | [ארגונים וסביבות עבודה](https://nodaro.ai/docs/developers/sdk/organizations) |
| `client.workspaces` | סביבות עבודה, חברים וקודי הצטרפות | [ארגונים וסביבות עבודה](https://nodaro.ai/docs/developers/sdk/organizations) |
| `client.userSettings` | ההגדרות שלכם: שפה, נראות בגלריה, הדוח החודשי במייל וההעדפות של תפריט **הוספת רכיב** ושל הקנבס | [הגדרות משתמש](#user-settings) |
| `client.developerApps` | אפליקציות ה-OAuth שבבעלותכם | [OAuth ויישומי מפתחים](https://nodaro.ai/docs/developers/sdk/developer-apps) |
| `client.oauth` | החלפת קוד באסימון, ביטול אסימונים ונתונים למסך ההסכמה | [OAuth ויישומי מפתחים](https://nodaro.ai/docs/developers/sdk/developer-apps) |

ללקוח עצמו יש עוד חמש מתודות: [`me()`](#me), [`connectedApps()`](#connectedapps), [`revokeConnectedApp()`](#revokeconnectedappauthorizationid), [`withWorkspace()`](#withworkspaceworkspaceid) ו-[`request()`](#requestmethod-path-options).

## נקודות כניסה לכל משאב
החבילה הראשית, `@nodaro/sdk`, מייצאת הכל. כל משאב מתפרסם גם כנקודת כניסה משלו, `@nodaro/sdk/<entry>`, שטוענת רק את המשאב הזה ואת הטיפוסים שהוא מקבל ומחזיר. למשל `@nodaro/sdk/jobs`, `@nodaro/sdk/nodes` ו-`@nodaro/sdk/workflows`.

- ב-`@nodaro/sdk/client` נמצאים `createClient`, `NodaroClient` וספקי האימות.
- ב-`@nodaro/sdk/core` נמצאים `NodaroClientCore` ואותם ספקי אימות.
- ב-`@nodaro/sdk/errors` נמצאות מחלקות השגיאה ו-`throwFromResponse`.
- כל נקודת כניסה אחרת נקראת על שם המשאב שלה. נקודת הכניסה `@nodaro/sdk/node-presets` היא `client.presets`, וב-`@nodaro/sdk/webhooks` נמצאת גם הפונקציה `verifyWebhookSignature`.

```ts

```

ערך שמייבאים מנקודת כניסה זהה לערך שמייבאים מהחבילה הראשית, ולכן בדיקת `instanceof NotFoundError` עובדת בלי קשר לנתיב שממנו כל צד ייבא. הפונקציה `createClient` בונה את כל המשאבים, ולכן נקודת הכניסה `@nodaro/sdk/client` טוענת את כולם. תת־הנתיבים הישנים `@nodaro/sdk/supabase` ו-`@nodaro/sdk/signup-signals` לא השתנו.

### לקוח עם המשאבים שאתם משתמשים בהם בלבד
המחלקה `NodaroClientCore` היא הלקוח בלי המשאבים שלו: האפשרויות ש-`createClient` מקבלת, מתודות הבקשה והמתודות `me()`, `connectedApps()` ו-`revokeConnectedApp()`. המחלקה `NodaroClient` מרחיבה אותה עם כל המשאבים. הרחיבו אותה בעצמכם רק עם המשאבים שאתם קוראים להם, והמודולים של שאר המשאבים לא נטענים אף פעם:

```ts

class AppClient extends NodaroClientCore {
readonly jobs = new JobsResource(this)
readonly nodes = new NodesResource(this) // polls through `jobs`
}

const client = new AppClient({ baseUrl: "https://app.nodaro.ai", auth: new StaticTokenAuth(token) })
await client.nodes.runAndWait("generate-image", { prompt: "a lighthouse at dusk" })
```

כל מחלקת משאב מקבלת `NodaroClientCore`. המחלקה `NodesResource` צריכה את `jobs` על אותו לקוח, והמחלקה `Scene3DResource` צריכה את `nodes`: הטיפוסים של הבנאים שלהן מציינים זאת, ולכן קוד שמשמיט אחד מהם לא עובר קומפילציה. המתודה `withWorkspace` שייכת ל-`NodaroClient`. כדי לעבוד בסביבת עבודה, העבירו את `workspaceId` לבנאי.

## מה המתודות מחזירות
- **המעטפות נשמרות.** כשנקודת קצה מחזירה `{ "data": ... }`, המתודה מחזירה את המעטפת הזו, ולכן כותבים `const { data } = await client.workflows.get(id)`. ברשימות עם עמודים יש גם cursor ליד `data`, כמו `nextCursor`.
- **חלק מהמשאבים מחזירים את המטען עצמו.** כמה מתודות פותחות את המעטפת של התגובה. למשל, המתודה `client.characters.list()` מחזירה `{ characters, nextCursor }`, והמתודה `client.credits.balance()` מחזירה את היתרה עצמה. בדף של כל משאב מופיע טיפוס ההחזרה המדויק.
- **מחיקות וביטולים** מחזירים בדרך כלל `{ success: true }`.
- **שמות השדות זהים לפורמט שה-API שולח.** השדות של `Job` כתובים ב-snake_case, כמו `output_data` ו-`created_at`, כי כך ה-API שולח אותם. השדות של `Workflow` ושל `WorkflowExecution` כתובים ב-camelCase.

כל טיפוס של תגובה ושל קלט מיוצא, כך שאפשר לייבא אותו עם `import type`. ראו את הדף [טיפוסים](https://nodaro.ai/docs/developers/sdk/types).

## me()‎
```ts
me(): Promise<UserIdentity & MeOrganizations>
```

מחזירה את הזהות שמאחורי האסימון הנוכחי (`GET /v1/me`). עם כל אסימון תקף, המתודה מחזירה את הבעלים שלו, בין שמדובר באסימון API, באסימון גישה של OAuth או בסשן בדפדפן. כשהאסימון חסר או לא תקין, המתודה זורקת `UnauthorizedError`.

```ts
const me = await client.me()
console.log(me.email, me.tier)
```

| שדה | סוג | תיאור |
| --- | --- | --- |
| `id` | `string` | מזהה המשתמש ב-Nodaro. |
| `email` | `string` | כתובת האימייל של המשתמש. |
| `displayName` | `string \| null` | שם התצוגה, או `null` כשהוא לא מוגדר. |
| `avatarUrl` | `string \| null` | כתובת ה-URL של האווטאר, או `null` כשהיא לא מוגדרת. |
| `tier` | `string` | רמת המנוי השמורה, כמו `"free"` או `"pro"`. כדי לדעת איזו רמה נאכפת בפועל, כולל תשלום לפי שימוש, קבלו את `effectiveTier` מ-[`client.credits.balance()`](https://nodaro.ai/docs/developers/sdk/models-and-credits). |
| `isAdmin` | `boolean` | האם המשתמש הוא מנהל מערכת. השתמשו בשדה רק כדי להחליט מה להציג. השרת בודק בעצמו כל הרשאה. |

במופע של Nodaro Cloud עם ארגונים, התוצאה כוללת גם את `organizations`, `workspaces`, `lastWorkspaceId` ו-`organizationsUnavailable`. טפלו בכל אחד משלושת המצבים שלהם בדרך אחרת:

| מה רואים | מה זה אומר | מה לעשות |
| --- | --- | --- |
| השדות לא מופיעים | במופע אין ארגונים | אל תציגו תפריט בחירת סביבת עבודה. |
| השדות מופיעים וריקים | החשבון לא שייך לאף ארגון | הציעו ליצור ארגון או להצטרף לארגון. |
| `organizationsUnavailable: true` | הבדיקה נכשלה | שמרו על הבחירה הקיימת. אל תגידו למשתמש שהוא איבד גישה. |

## connectedApps()‎
```ts
connectedApps(): Promise<ConnectedApp[]>
```

מחזירה כל אפליקציה שיש לה גישה לחשבון של המשתמש המחובר (`GET /v1/me/connected-apps`), לפי מועד אישור הגישה, מהחדש לישן. הרשימה כוללת יישומי מפתחים, מחברי MCP של עוזרי AI והתקנות באירוח עצמי. אלה הנתונים שמסך הגדרות של **אפליקציות מחוברות** מציג. ראו את הדף [אפליקציות OAuth](https://nodaro.ai/docs/developers/oauth) כדי להבין מהו אישור גישה.

**המתודה הזו דורשת סשן מחובר בדפדפן.** היא מקבלת אסימון סשן מ-[`supabaseAuth()`](https://nodaro.ai/docs/developers/sdk/auth#supabaseauthsupabase) או מ-`createSharedSupabaseClient`. עם אסימון API (`ndr_…`) או אסימון של אפליקציה (`ndr_app_…`) היא זורקת `UnauthorizedError`, כך שאפליקציה לא יכולה לקבל רשימה של אישורי הגישה שהיא משתמשת בהם או לבטל אותם. אינטגרציה בצד השרת לא יכולה לקרוא לה.

```ts
const apps = await client.connectedApps()
// [{ authorizationId, name, kind, homepageUrl, scopes, connectedAt, lastUsedAt }]
```

| שדה | סוג | תיאור |
| --- | --- | --- |
| `authorizationId` | `string` | אישור הגישה. העבירו אותו ל-`revokeConnectedApp()`. |
| `name` | `string \| null` | שם האפליקציה. לקוח MCP שרשם את עצמו בחר את השם שלו בעצמו. |
| `kind` | `DeveloperAppKind` | `user` (יישום מפתחים), `first_party_mcp`, `dynamic_mcp` (לקוח MCP שרשם את עצמו) או `community_instance` (התקנה באירוח עצמי). |
| `homepageUrl` | `string \| null` | דף הבית של האפליקציה, אם היא ציינה אחד. |
| `scopes` | `DeveloperAppScope[]` | ההרשאות שבאישור הגישה. |
| `connectedAt` | `string` | מתי המשתמש אישר את הגישה, בפורמט ISO 8601. |
| `lastUsedAt` | `string \| null` | השימוש האחרון באסימון כלשהו שהונפק במסגרת אישור הגישה, או `null` אם אף פעם לא השתמשו בו. |

## revokeConnectedApp(authorizationId)‎
```ts
revokeConnectedApp(authorizationId: string): Promise<void>
```

מסיימת את הגישה של אפליקציה (`POST /v1/me/connected-apps/:authorizationId/revoke`). המתודה מבטלת מיד את אישור הגישה ואת כל אסימון שהונפק במסגרתו, ולכן הקריאה הבאה של האפליקציה נכשלת עם 401. כמו `connectedApps()`, גם היא דורשת סשן מחובר בדפדפן. כשאישור הגישה לא שייך למשתמש, או שהוא כבר בוטל, המתודה זורקת `NotFoundError`.

```ts
await client.revokeConnectedApp(app.authorizationId)
```

## client.userSettings
המשאב `client.userSettings` קורא ומשנה את ההגדרות של האדם המחובר עצמו: שפת הממשק, הנראות בגלריה, הדוח החודשי במייל וההעדפות של תפריט **הוספת רכיב** ושל הקנבס. אפשר גם לייבא אותו מ-`@nodaro/sdk/user-settings`. אפליקציה מציגה את ההגדרות שהיא צריכה, ושולחת בחזרה רק את השדות שהיא משנה.

| מתודה | נקודת קצה | הערות |
| --- | --- | --- |
| `get()` | `GET /v1/user/settings` | מחזירה `UserSettings`: `{ tier, publicOutputs, promptTemplates, textTemplates, preferredLocale, mcpPreferences, showRecentNodes, showMostUsedNodes, variableDisplayMode, nodeDoubleClickAction, monthlyStatementEmail }`. כשאף אחד לא מחובר, היא זורקת `UnauthorizedError`. |
| `update(patch)` | `PATCH /v1/user/settings` | משנה רק את השדות שאתם שולחים, ומחזירה את ההגדרות כפי שנשמרו, בלי `tier`. |

כללים ל-`update(patch)`:

- השדות `promptTemplates` ו-`textTemplates` מחליפים את הערך השמור כולו, ולכן שלחו את המפה או את הרשימה המלאה. השרת משמיט מפתח תבנית שהוא לא מכיר, וגם ערך ששווה לברירת המחדל.
- השדה `mcpPreferences` ממוזג ציר אחר ציר.
- הערך `publicOutputs: false` דורש ב-Nodaro Cloud את תוכנית Standard ומעלה. אחרת המתודה זורקת `ForbiddenError`.
- השדה `preferredLocale` מקבל אחת מהשפות ש-Nodaro תומך בהן (`UserSettingsLocale`).
- כשערך לא תקין, או כשאין ב-`patch` מה לשנות, המתודה זורקת `NodaroError` עם סטטוס 400 (`validation_error`). כשהפרופיל חסר, היא זורקת `NotFoundError`.

```ts
// The monthly statement toggle on a billing screen.
const { monthlyStatementEmail } = await client.userSettings.get()
await client.userSettings.update({ monthlyStatementEmail: !monthlyStatementEmail })
```

הטיפוסים הם `UserSettings`, `UserSettingsPatch`, `UserSettingsSaved`, `UserSettingsLocale`, `UserTextTemplate`, `UserMcpPreferences`, `VariableDisplayMode` ו-`NodeDoubleClickAction`.

## withWorkspace(workspaceId)‎
```ts
withWorkspace(workspaceId: string | null): NodaroClient
```

מחזירה לקוח **חדש** שפועל ב-`workspaceId`. הלקוח החדש חולק עם המקורי את האימות, את כתובת הבסיס, את פסק הזמן ואת פונקציית ה-fetch. העבירו `null` כדי לעבוד במרחב האישי שלכם.

```ts
const classroom = client.withWorkspace(workspaceId)

await classroom.workflows.run(workflowId) // runs in the workspace
await client.workflows.run(workflowId)    // runs in the personal space
```

המתודה מחזירה לקוח חדש במקום לשנות את הלקוח הנוכחי. לכן שתי פעולות שרצות באותו זמן על אותו לקוח אף פעם לא מתבלבלות בין סביבות העבודה שלהן.

סביבת העבודה קובעת את **ההיקף**, אף פעם לא את **הגישה**. היא בוחרת מאיזו סביבת עבודה נקראת רשימה, ואיפה נוצר פריט חדש. קריאה, שינוי, מחיקה או הרצה של פריט שאתם מציינים לפי מזהה נקבעים לפי סביבת העבודה של הפריט עצמו. כששוכחים לציין סביבת עבודה, העבודה שלכם לא נעלמת, וסביבת עבודה שגויה לא נותנת גישה לעבודה של אף אחד אחר.

ב-Nodaro Cloud, סביבות עבודה שייכות לארגונים. ראו את הדפים [ארגונים וסביבות עבודה](https://nodaro.ai/docs/developers/sdk/organizations) ו[סביבות עבודה](https://nodaro.ai/docs/concepts/workspaces).

## request(method, path, options)‎
```ts
request<T>(method: string, path: string, options?: {
body?: unknown
query?: Record<string, string | number | boolean | undefined>
headers?: Record<string, string>
signal?: AbortSignal
}): Promise<T>
```

שולחת בקשה לכל נקודת קצה, בשביל נקודות הקצה המעטות שעדיין אין להן מתודה במשאב. המתודה מוסיפה את כותרת האימות ואת סביבת העבודה שלכם, שולחת את `body` כ-JSON, מחילה את `timeoutMs` וזורקת את אותן [שגיאות עם טיפוסים](https://nodaro.ai/docs/developers/sdk/errors) כמו מתודות המשאבים.

```ts
// The same request that client.jobs.list() sends
const page = await client.request<{ data: unknown[]; next: string | null }>("GET", "/v1/jobs", {
query: { type: "llm-structured", limit: 20 },
})
```

גוף מסוג `FormData` נשלח כהעלאת multipart. ערכי שאילתה שהם `undefined` מושמטים. [מדריך ה-REST API](https://nodaro.ai/docs/developers/api) מפרט את כל נקודות הקצה ואת השדות שלהן.

## פסקי זמן ו-fetch משלכם
האפשרות `timeoutMs` מבטלת בקשה שנמשכת יותר מהמגבלה, 60 שניות כברירת מחדל. רוב היצירות נמשכות יותר מכל פסק זמן סביר של HTTP, ולכן התחילו את היצירה ובדקו את סטטוס המשימה מדי כמה שניות: המתודה [`client.nodes.runAndWait()`](https://nodaro.ai/docs/developers/sdk/nodes) עושה את שני הדברים בשבילכם. מתודות ההזרמה, `client.copilot.stream()` ו-`client.media.downloadVideoProgress()`, לא מחילות את פסק הזמן, כי הן אמורות להישאר פתוחות במשך דקות.

העבירו `fetch` משלכם כדי לשנות את הדרך שבה הבקשות נשלחות:

- **בדיקות.** החזירו מ-mock אובייקטי `Response` מוכנים מראש.
- **ניסיונות חוזרים.** עטפו את `fetch` הגלובלי בפונקציית עזר שמנסה שוב כשמתקבלת תשובה 5xx.
- **מעקב.** עטפו אותו בספריית המעקב או הניטור שלכם.

```ts
const client = createClient({
baseUrl: "https://app.nodaro.ai",
auth: new StaticTokenAuth(process.env.NODARO_TOKEN!),
fetch: (input, init) => tracedFetch(input, init),
})
```

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

- **CORS עם אסימוני OAuth.** אפליקציית דפדפן שקוראת ל-Nodaro עם אסימון גישה של OAuth חייבת לרוץ על origin שמופיע ב-`allowedOrigins` של יישום המפתחים. ראו את הדף [OAuth ויישומי מפתחים](https://nodaro.ai/docs/developers/sdk/developer-apps).
- **CORS עם סשן.** אפליקציית דפדפן שמשתמשת ב-`supabaseAuth` לא נבדקת מול הרשימה הזו.
- **תווית הלקוח.** בשרת, ה-SDK שולח `X-Nodaro-Client: sdk/<version>`, ו-Nodaro רושם אותה כמקור של כל משימה. בדפדפן, תווית ברירת המחדל לא נשלחת, כי כותרת ה-`Origin` של הדפדפן כבר מציינת את האפליקציה שלכם. ערך `clientLabel` שהגדרתם בעצמכם נשלח תמיד.

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

### באיזו כתובת בסיס להשתמש עם ה-SDK של Nodaro?

כתובת הבסיס של ה-SDK היא https://app.nodaro.ai ב-Nodaro Cloud, והכתובת של המופע שלכם בהתקנה באירוח עצמי. באפליקציית דפדפן שמוגשת מאותו origin כמו Nodaro, השתמשו במחרוזת ריקה.

### מהו פסק הזמן של בקשה כברירת מחדל?

פסק הזמן של כל בקשה הוא 60 שניות כברירת מחדל, ואפשר לשנות אותו באפשרות timeoutMs. יצירה נמשכת יותר זמן מכל בקשה, ולכן התחילו אותה ובדקו את סטטוס המשימה מדי כמה שניות, במקום להגדיל את פסק הזמן.

### איך שולחים בקשות שפועלות בסביבת עבודה?

כדי לשלוח בקשות בסביבת עבודה, קראו ל-client.withWorkspace(workspaceId)‎. המתודה מחזירה לקוח חדש שכל בקשה שלו פועלת בסביבת העבודה הזו, והלקוח המקורי ממשיך לעבוד במרחב האישי שלכם.

### איך קוראים לנקודת קצה שאין לה מתודה ב-SDK?

לנקודת קצה שאין לה מתודה ב-SDK, קראו ל-client.request(method, path, options)‎. המתודה שולחת את אותה כותרת אימות, מחילה את אותו פסק זמן וזורקת את אותן שגיאות עם טיפוסים כמו כל מתודה של משאב.
