---
url: https://docs.ogmabox.com/fa/plugins/README.md
description: >-
  افزونه‌های Ogma را با منطق بک‌اند، پنل‌های فرانت‌اند، فرمان‌ها، مجوزها و
  فرادادهٔ بازارچه بسازید، بسته‌بندی، نصب، فعال و توزیع کنید.
---

# نظام افزونه‌های Ogma {#ogma-plugin-system}

افزونه‌های Ogma ابزار را با منطق سفارشی بک‌اند، پنل‌های رابط کاربری فرانت‌اند و مراحل گردش کار گسترش می‌دهند. افزونه‌ها به‌صورت محلی از یک پوشه روی دیسک نصب می‌شوند، برای هر پروژه فعال می‌شوند و در یک محیط ایزوله اجرا می‌شوند.

این سند مرجع اصلی نویسندگان افزونه است.

برای سریع‌ترین شروع ممکن، از [شروع سریع افزونه‌ها](/fa/plugins/quickstart) استفاده کنید.

***

## شروع سریع {#quick-start}

### افزونهٔ سادهٔ بک‌اند {#minimal-backend-plugin}

```
my-plugin/
  manifest.json
  backend/script.js
```

`manifest.json`:

```json
{
  "id": "my-plugin",
  "name": "My Plugin",
  "version": "1.0.0",
  "plugins": [
    {
      "kind": "backend",
      "id": "my-plugin-backend",
      "entrypoint": "backend/script.js"
    }
  ]
}
```

`backend/script.js` (ES2020؛ هنگام استفاده از ابزار بسته‌بندی، استفاده از دستورهای واردسازی مجاز است):

```js
async function init(sdk) {
  sdk.console.log("my-plugin started");

  sdk.events.onInterceptResponse(function(req, res) {
    if (res.getCode() === 403) {
      sdk.console.warn("403 on " + req.getUrl());
    }
  });
}
```

این برای یک افزونهٔ عملیاتی فقط با بک‌اند کافی است. آن را به‌صورت یک فایل واحد در `backend/script.js` نگه دارید و `manifest.json` را مستقیماً به آن ارجاع دهید.

### روند ساخت یک‌دقیقه‌ای (منبع TypeScript) {#one-minute-build-flow-typescript-source}

اگر با TypeScript کدنویسی می‌کنید، از این ساختار استفاده کنید:

```text
my-plugin/
  manifest.json
  backend/
    src/index.ts
```

ساخت:

```bash
pnpm add -D @ogmabox/ogma-sdk esbuild typescript
pnpm exec esbuild backend/src/index.ts --bundle --format=iife --platform=neutral --external:@ogma/sdk --external:@ogmabox/ogma-sdk --outfile=backend/script.js
```

نصب: **افزونه‌ها > نصب**، پوشهٔ `my-plugin/` را انتخاب کنید. سپس افزونه را فعال کنید.

***

## مرجع مانیفست {#manifest-reference}

`manifest.json` در پوشهٔ ریشهٔ بسته قرار دارد. تمام فیلدها به بزرگی و کوچکی حروف حساس هستند.

### فیلدهای سطح بالا {#top-level-fields}

| فیلد | الزامی | نوع | توضیحات |
|-------|----------|------|-------|
| `id` | بله | رشته | فقط حروف کوچک لاتین، رقم‌ها و خط تیره. حداکثر 64 نویسه. در میان افزونه‌های نصب‌شده یکتا است. |
| `version` | بله | رشته | نسخه‌بندی معنایی: `MAJOR.MINOR.PATCH` |
| `name` | خیر | رشته | نام نمایشی در رابط کاربری. پیش‌فرض آن `id` است. |
| `description` | خیر | رشته | خلاصهٔ یک‌خطی. |
| `author` | خیر | شیء | `{ "name": "...", "email": "...", "url": "..." }` |
| `homepage` | خیر | رشته | نشانی URL مخزن منبع یا مستندات. |
| `plugins` | بله | آرایه | یک یا چند مدخل جزء افزونه (پایین را ببینید). |
| `permissions` | خیر | آرایه | فهرست نام مجوزهای مورد نیاز (به [مجوزها](#permissions) مراجعه کنید). |

### مدخل جزء افزونه {#plugin-component-entry}

هر شیء در آرایهٔ `plugins` یک جزء را توصیف می‌کند.

**جزء بک‌اند:**

```json
{
  "kind": "backend",
  "id": "my-plugin-backend",
  "entrypoint": "backend/script.js",
  "runtime": "javascript",
  "assets": "backend/assets"
}
```

**جزء فرانت‌اند:**

```json
{
  "kind": "frontend",
  "id": "my-plugin-frontend",
  "entrypoint": "frontend/script.js",
  "style": "frontend/style.css",
  "assets": "frontend/assets",
  "backend": { "id": "my-plugin-backend" }
}
```

| فیلد | الزامی | توضیحات |
|-------|----------|-------|
| `kind` | بله | `"backend"` یا `"frontend"` |
| `id` | بله | در مانیفست یکتا است. حروف کوچک و خط تیره. |
| `entrypoint` | بله | مسیر نسبی فایل ورودی JS. |
| `style` | خیر | فایل CSS که در iframe افزونه بارگذاری می‌شود. |
| `assets` | خیر | پوشهٔ منابع ثابت که زیر `/plugins/{id}/assets/` ارائه می‌شوند. |
| `backend.id` | خیر | یک جزء فرانت‌اند را برای RPC از طریق `sdk.backend.*` به جزء بک‌اند آن پیوند می‌دهد. |
| `runtime` | خیر (فقط بک‌اند) | `"javascript"` (مقدار پیش‌فرض و تنها مقدار پشتیبانی‌شده). |

***

## API افزونهٔ بک‌اند (sdk) {#backend-plugin-api-sdk}

شیء `sdk` بک‌اند به تابع `init(sdk)` شما داده می‌شود. همهٔ متدها همگام هستند، مگر اینکه با `async` مشخص شده باشند.

### `sdk.console` {#sdk-console}

```js
sdk.console.log("message")
sdk.console.warn("message")
sdk.console.error("message")
```

در بافر گزارش رویدادهای افزونه می‌نویسد (در زبانهٔ گزارش رویدادها دیده می‌شود). حداکثر 500 مدخل نگه داشته می‌شود. هر پیام در 1 KB کوتاه می‌شود.

### `sdk.meta` {#sdk-meta}

```js
sdk.meta.id()          // > string: plugin id (e.g. "my-plugin")
sdk.meta.packageId()   // > string: same as id
sdk.meta.version()     // > string: semver (e.g. "1.0.0")
sdk.meta.path()        // > string: writable data directory for this plugin
```

`sdk.meta.path()` به پوشهٔ خصوصی و قابل نوشتن داده‌های افزونه اشاره می‌کند؛ مثلاً `~/.local/share/ogma/plugins/my-plugin/data`. پوشه به‌طور خودکار ایجاد می‌شود و می‌توان از آن برای نگهداری پایدار داده‌های افزونه در راه‌اندازی‌های مجدد استفاده کرد.

`sdk.storage`، `sdk.path` و `sdk.fs` نیز برای ابزارهای کمکی وضعیت و فایل در دسترس هستند.

### `sdk.storage` {#sdk-storage}

```js
sdk.storage.get("key")      // > string | null
sdk.storage.set("key", "value")
sdk.storage.delete("key")
sdk.storage.clear()
sdk.storage.keys()          // > string[]
```

`sdk.storage` به شناسهٔ افزونه محدود است و در راه‌اندازی‌های مجدد افزونه حفظ می‌شود.

### `sdk.fs` {#sdk-fs}

```js
sdk.fs.readFile("relative/file.txt")      // > string
sdk.fs.writeFile("relative/file.txt", "text")
sdk.fs.appendFile("relative/file.txt", "more")
sdk.fs.exists("relative/file.txt")        // > boolean
sdk.fs.existsSync("relative/file.txt")    // > boolean
sdk.fs.list("relative/dir")              // > string[]
sdk.fs.mkdir("relative/dir")
```

`sdk.fs` به فایل‌های زیر `sdk.meta.path()` محدود است.

`read` و `write` همچنان نام‌های مستعار سازگاری برای `readFile` و `writeFile` هستند. پیش از ایجاد فایلی که نمی‌خواهید بازنویسی شود، از `exists` یا `existsSync` استفاده کنید. این APIها در محیط اجرای افزونه به‌صورت همگام کار می‌کنند؛ آن‌ها ماژول کامل `fs` در Node.js نیستند. دسترسی افزونه به فایل به مجوز `plugin_storage` نیاز دارد و در پوشهٔ خصوصی داده‌های افزونه باقی می‌ماند. JavaScript گردش کار زمینهٔ متفاوتی برای سیستم فایل دارد؛ به [دسترسی گردش کار به فایل](../app/workflows.md#javascript-and-files) مراجعه کنید.

### `sdk.path` {#sdk-path}

```js
sdk.path.join("a", "b", "c")
sdk.path.basename("/tmp/file.txt")
sdk.path.dirname("/tmp/file.txt")
sdk.path.extname("file.txt")
sdk.path.resolve("/a", "b")
sdk.path.isAbsolute("/tmp/file.txt")
sdk.path.sep
```

### `sdk.events` {#sdk-events}

توابع فراخوانی برگشتی را برای رویدادهای Ogma ثبت کنید. همهٔ این توابع به‌صورت همگام در محیط ایزولهٔ QuickJS فراخوانی می‌شوند.

```js
sdk.events.onInterceptRequest(function(req) {
  // req: RequestSpecRaw
  // Return a modified RequestSpecRaw to mutate the request.
  // Return null/undefined to pass through unchanged.
});

sdk.events.onInterceptResponse(function(req, res) {
  // req: Request (read-only), res: Response (read-only)
  // Return value is ignored.
});

sdk.events.onProjectChange(function() {
  // no callback args
});

sdk.events.onFindingCreated(function(finding) {
  // finding: { id, title, reporter }
});
```

### `sdk.requests` {#sdk-requests}

```js
// Get a single HTTP entry by id
var entry = sdk.requests.get("entry-id");
// entry: { id, method, host, path, query, tls, ... } or null

// Search HTTP history
var results = sdk.requests.search({ limit: 20, offset: 0 });
// results: { entries: [...], total: N }

// Send an HTTP request (requires send_requests permission)
var response = await sdk.requests.send(spec);
// spec: RequestSpecRaw (see below)
// response: Response
```

`sdk.requests.send` نیاز دارد مجوز `send_requests` در مانیفست اعلام و توسط کاربر اعطا شود. به [مجوزها](#permissions) مراجعه کنید.

### `sdk.findings` {#sdk-findings}

```js
// Create a finding (requires write_findings permission)
sdk.findings.create({
  title: "SSRF via redirect",
  reporter: "my-plugin",
  dedupeKey: "ssrf-" + request.getId(),
  request: { id: request.getId() }
});

// Check if a finding already exists (dedup check)
var exists = sdk.findings.exists({ dedupeKey: "ssrf-abc" });

// List findings
var page = sdk.findings.list({ limit: 20, offset: 0 });

// Get a single finding
var finding = sdk.findings.get("finding-id");
```

محدودیت نرخ برای `sdk.findings.create`: ‏10 در دقیقه، 500 در هر نشست افزونه و 3 در هر تابع فراخوانی برگشتی رویداد.

### `sdk.api` {#sdk-api}

توابع RPC بک‌اند را ثبت کنید تا فرانت‌اند بتواند از طریق `sdk.backend.*` آن‌ها را فراخوانی کند:

```js
// In backend init:
sdk.api.register("getScans", function(scanId) {
  return { scans: [] };
});

// Emit an event to connected frontends:
sdk.api.send("scan:complete", { scanId: 1, status: "ok" });
```

پردازشگر آرگومان‌های ارسال‌شده از فرانت‌اند را دریافت می‌کند (آرگومان اضافی `sdk` تزریق نمی‌شود). مقادیر بازگشتی به‌صورت JSON سریال‌سازی و به فراخواننده ارسال می‌شوند.

فرانت‌اند آن‌ها را از طریق `sdk.backend.getScans(scanId)` فراخوانی می‌کند - به [API افزونهٔ فرانت‌اند](#frontend-plugin-api-sdk) مراجعه کنید.

`sdk.api.send` رویدادها را به صفی مخصوص هر افزونه می‌فرستد (حداکثر 200 مدخل). فرانت‌اندها این صف را از طریق `sdk.backend.onEvent` پایش می‌کنند.

### `sdk.replay`, `sdk.projects`, `sdk.scope`, `sdk.workflows`, `sdk.matchReplace` {#sdk-replay-sdk-projects-sdk-scope-sdk-workflows-sdk-matchreplace}

این‌ها فضاهای نام جست‌وجوی فقط‌خواندنی هستند. برای امضای کامل متدها، به [مرجع SDK بک‌اند](./backend-sdk.md) مراجعه کنید.

### کلاس‌های درخواست {#request-classes}

**`RequestSpecRaw`** - نمایندهٔ یک درخواست رهگیری‌شده است. آن را در `onInterceptRequest` دریافت می‌کنید.

```js
spec.getMethod()          // > string
spec.setMethod("POST")
spec.getHost()            // > string
spec.setHost("example.com")
spec.getPort()            // > number
spec.getPath()            // > string
spec.setPath("/new/path")
spec.getQuery()           // > string
spec.getTls()             // > boolean
spec.getHeaders()         // > Record<string, string[]>
spec.setHeader("X-Foo", "bar")
spec.getBody()            // > Body | null
spec.setBody("new body")
spec.getRaw()             // > Uint8Array (raw bytes) or []
spec.setRaw(bytes)        // set raw bytes

// Create a new spec from a URL string:
var spec = new RequestSpecRaw("https://example.com/path?q=1");
```

**`Request`** - یک درخواست ثبت‌شدهٔ فقط‌خواندنی (از `sdk.requests.get`).

```js
req.getId()
req.getMethod()
req.getHost()
req.getPort()
req.getTls()
req.getPath()
req.getQuery()
req.getUrl()           // > full URL string
req.getHeaders()       // > Record<string, string>
req.getHeader("name")
req.getBody()          // > Body | null
req.getCreatedAt()     // > Date
req.toSpec()           // > RequestSpec (mutable copy)
```

**`Response`** - یک پاسخ ثبت‌شدهٔ فقط‌خواندنی.

```js
res.getCode()            // > number (HTTP status)
res.getHeaders()         // > Record<string, string>
res.getHeader("name")
res.getBody()            // > Body | null
res.getRoundtripTime()   // > number (ms)
res.getCreatedAt()       // > Date
```

**`Body`**:

```js
body.toText()    // > string
body.toJson()    // > parsed object or null
body.toRaw()     // > Uint8Array
body.length      // > number (original size, may differ from toText() if truncated)
```

***

## API افزونهٔ فرانت‌اند (sdk) {#frontend-plugin-api-sdk}

کد افزونهٔ فرانت‌اند در یک iframe ایزوله اجرا می‌شود که از `/plugins/{id}/ui` بارگذاری شده است. iframe برای ارتباط با میزبان Ogma از `postMessage` استفاده می‌کند و میزبان فراخوانی‌ها را به بک‌اند منتقل می‌کند.

SDK از طریق `window.ogmaSDK` در دسترس است. `ogmaSDK.ready(cb)` را فراخوانی کنید تا پس از برقراری پل میزبان، SDK آمادهٔ استفاده را دریافت کنید:

```js
ogmaSDK.ready(function(sdk) {
  // sdk is the live SDK - safe to call any method here
  sdk.log.info("frontend ready");
});
```

همهٔ متدهای SDK، Promise برمی‌گردانند.

### `sdk.log` {#sdk-log}

```js
sdk.log.info("message")
sdk.log.warn("message")
sdk.log.error("message")
```

### `sdk.meta` {#sdk-meta-1}

```js
var meta = await sdk.meta.get();
// { pluginId, packageId, name, version, ogmaVersion }
```

### `sdk.requests` {#sdk-requests-1}

```js
var entry = await sdk.requests.get({ id: "entry-id" });
var result = await sdk.requests.search({ limit: 20, offset: 0, query: "host:example.com" });
```

به مجوز `read_http_history` نیاز دارد (به‌طور خودکار اعطا می‌شود؛ تأیید کاربر لازم نیست).

### `sdk.findings` {#sdk-findings-1}

```js
var page = await sdk.findings.list({ limit: 20, offset: 0 });
```

به مجوز `read_findings` نیاز دارد (به‌طور خودکار اعطا می‌شود).

### `sdk.scope` {#sdk-scope}

```js
var scope = await sdk.scope.getActive();
```

### `sdk.projects` {#sdk-projects}

```js
var project = await sdk.projects.getCurrent();
```

### `sdk.backend` - RPC بک‌اند {#sdk-backend-backend-rpc}

توابع ثبت‌شده با `sdk.api.register` در بک‌اند را فراخوانی کنید:

```js
// Call a named backend function
var result = await sdk.backend.call("getScans", [scanId]);

// Poll for backend-emitted events (sdk.api.send on the backend side)
var { events, next_since } = await sdk.backend.poll(since);
// events: [{ event: "scan:complete", args: [...] }]

// Register an event listener (uses polling internally)
sdk.backend.onEvent("scan:complete", function(data) {
  console.log("scan done", data);
});
```

`sdk.backend.onEvent` در داخل از یک حلقهٔ پایش با فاصلهٔ 2 ثانیه استفاده می‌کند. با فراخوانی تابع لغو اشتراک بازگشتی، دریافت رویدادها را متوقف کنید:

```js
var unsub = sdk.backend.onEvent("scan:complete", handler);
// later:
unsub();
```

### `sdk.navigation` {#sdk-navigation}

```js
await sdk.navigation.addPage("/my-plugin", { title: "My Plugin" });
```

یک صفحهٔ پیمایش ثبت می‌کند. در حال حاضر میزبان آن را تأیید می‌کند. یکپارچه‌سازی کامل مسیریاب در حال انجام است.

### `sdk.sidebar` {#sdk-sidebar}

```js
await sdk.sidebar.registerItem("My Plugin", "/my-plugin", { icon: "puzzle" });
```

یک مدخل نوار کناری ثبت می‌کند. در حال حاضر به پنل رابط کاربری افزونه محدود است - اتصال به جایگاه نوار کناری سراسری در حال انجام است.

### `sdk.commands` {#sdk-commands}

```js
await sdk.commands.register("my-plugin:scan", {
  name: "Scan with My Plugin",
  handler: function(context) { /* ... */ }
});
```

میزبان تأیید می‌کند. یکپارچه‌سازی با پالت فرمان در حال انجام است.

### `sdk.menu` {#sdk-menu}

```js
await sdk.menu.registerItem({
  type: "Request",
  commandId: "my-plugin:scan",
  leadingIcon: "shield"
});
```

میزبان تأیید می‌کند. افزودن به منوی زمینه‌ای در حال انجام است.

### `sdk.window` {#sdk-window}

```js
sdk.window.showToast("Scan complete", { variant: "success", duration: 3000 });
```

یک اعلان گذرا در پنل افزونه نمایش می‌دهد. گونه‌ها: `info`، `success`، `warning`، `error`.

### `sdk.ui` {#sdk-ui}

```js
sdk.ui.resize(600);                              // request iframe height change
sdk.ui.sidebar.registerItem("name", "/path");    // alias for sdk.sidebar.registerItem
```

***

## مجوزها {#permissions}

مجوزها را در `manifest.json` اعلام کنید:

```json
{
  "permissions": ["send_requests", "write_findings"]
}
```

### مجوزهای خودکار (بدون نیاز به تأیید کاربر) {#auto-granted-permissions-no-user-approval-needed}

این مجوزها همیشه به هر افزونهٔ نصب‌شده اعطا می‌شوند:

| مجوز | آنچه مجاز می‌کند |
|------------|----------------|
| `read_http_history` | `sdk.requests.get`, `sdk.requests.search` |
| `read_findings` | `sdk.findings.get`, `sdk.findings.list` |
| `read_scope` | `sdk.scope.getActive` |
| `read_projects` | `sdk.projects.getCurrent`, `sdk.projects.list` |
| `plugin_storage` | `sdk.storage`, `sdk.fs`, `sdk.path` |

### مجوزهای محافظت‌شده (نیازمند تأیید کاربر) {#protected-permissions-require-user-approval}

این مجوزها باید در مانیفست اعلام شوند و کاربر از زبانهٔ مجوزها صریحاً آن‌ها را اعطا کند:

| مجوز | آنچه مجاز می‌کند |
|------------|----------------|
| `send_requests` | `sdk.requests.send` - ارسال درخواست‌های HTTP خروجی |
| `write_findings` | `sdk.findings.create`, `sdk.findings.update` |

کاربر هنگام فعال‌سازی افزونه‌ای که مجوزهای محافظت‌شده اعلام می‌کند، یک پیام درخواست مجوز می‌بیند. او همچنین می‌تواند هر زمان از زبانهٔ مجوزها مجوزها را اعطا یا لغو کند.

***

## ساختار بستهٔ افزونه {#plugin-package-structure}

بستهٔ افزونه را می‌توان از یک پوشهٔ محلی و در روندهای مرورگر، از خروجی‌های `.zip` نیز نصب کرد.

```
my-plugin/
  manifest.json           - required
  backend/
    script.js             - bundled backend JS (ES2020)
  frontend/
    script.js             - bundled frontend JS
    style.css             - optional CSS
    assets/               - static assets (images, fonts, etc.)
```

### الزامات اسکریپت بک‌اند {#backend-script-requirements}

* باید یک فایل JS واحد و مستقل باشد.
* `require()` و `import()` پویا پشتیبانی نمی‌شوند.
* باید تابع `init(sdk)` را صادر کند (یا آن را به‌صورت سراسری تعریف کند).
* زیرمجموعهٔ ES2020 پشتیبانی‌شده در QuickJS: ‏`async/await`، `Promise`، `Map`، `Set`، `Symbol`، `Proxy`، `Date`، `RegExp`، `JSON`. بدون `fetch` و بدون `Buffer`.
* واردسازی‌های ایستای پشتیبانی‌شده در پیش‌پردازش افزونه حل می‌شوند: `@ogma/sdk`، `crypto`، `fs`، `path`.
* حداکثر اندازهٔ فایل: 256 KB.

### الزامات اسکریپت فرانت‌اند {#frontend-script-requirements}

* در یک iframe ایزوله اجرا می‌شود. `connect-src: 'self'` مجاز است تا افزونه بتواند به `/plugins/{id}/api/*` درخواست POST بفرستد و `/plugins/{id}/events/poll` را پایش کند.
* سیاست CSP: ‏`default-src 'none'; script-src 'nonce-...'; style-src 'self'; img-src data: blob: 'self'; connect-src 'self'`.
* در محیط ایزولهٔ iframe، ‏`allow-same-origin` وجود ندارد - افزونه نمی‌تواند به DOM والد Ogma یا کوکی‌ها دسترسی داشته باشد.
* برای دسترسی به SDK از `ogmaSDK.ready(cb)` استفاده کنید؛ پیش از اجرای تابع فراخوانی برگشتی، متدهای SDK را فراخوانی نکنید.

***

## ساخت افزونه برای Ogma {#building-a-plugin-for-ogma}

چون بک‌اند باید یک فایل JS بسته‌بندی‌شدهٔ واحد باشد، لازم است پیش از نصب، منبع TypeScript یا ماژول ES خود را بسته‌بندی کنید.

زنجیرهٔ ابزار پیشنهادی:

```bash
# Install dependencies
pnpm install

# Bundle backend (outputs a single CJS/IIFE file):
esbuild packages/backend/src/index.ts \
  --bundle \
  --platform=neutral \
  --format=iife \
  --global-name=_plugin \
  --outfile=dist/backend/script.js \
  --external:@ogma/sdk --external:@ogmabox/ogma-sdk

# Bundle frontend:
vite build packages/frontend --outDir ../../dist/frontend
```

اگر از زنجیرهٔ ابزار توسعهٔ Caido‏ (`@caido-community/dev`) استفاده می‌کنید، `caido-dev build` را اجرا کنید و سپس خروجی را در ساختاری سازگار با Ogma کپی کنید که `manifest.json` در ریشهٔ آن قرار دارد.

***

## نصب افزونه {#installing-a-plugin}

1. **افزونه‌ها** را در نوار کناری سمت چپ باز کنید.
2. روی **نصب** کلیک کنید (بالای زبانهٔ **نصب‌شده**).
3. در برنامهٔ دسکتاپ، روی **مرور** کلیک کنید تا انتخابگر بومی پوشه باز شود. در مرورگر، مسیر کامل پوشهٔ افزونه در سمت سرور را وارد کنید.
4. روی **اعتبارسنجی** کلیک کنید تا مانیفست و فهرست فایل‌ها بررسی شوند.
5. اگر اعتبارسنجی موفق بود، روی **نصب** کلیک کنید.
6. افزونه را از فهرست انتخاب کنید و روی **فعال‌سازی** کلیک کنید.
7. اگر افزونه مجوزهای محافظت‌شده اعلام می‌کند، پیش از فعال‌سازی آن‌ها را از زبانهٔ **مجوزها** بررسی و اعطا کنید.

***

## رفع اشکال {#troubleshooting}

**راه‌اندازی افزونه بدون پیام خطا شکست می‌خورد:** زبانهٔ **گزارش رویدادها** را بررسی کنید. رایج‌ترین دلایل:

* `sdk.meta.path()` فراخوانی شده اما پوشهٔ داده ایجاد نشده است.
* یک استثنای مدیریت‌نشده در `init()`.
* فراخوانی `sdk.*` وجود ندارد یا اشتباه نوشته شده است.

**فرانت‌اند خالی نمایش داده می‌شود:** کنسول مرورگر را برای نقض‌های CSP بررسی کنید. مطمئن شوید اسکریپت فرانت‌اند پیش از دسترسی به هر متد SDK، ‏`ogmaSDK.ready(cb)` را فراخوانی می‌کند.

**`sdk.requests.send` خطای `Permission denied` می‌دهد:** مجوز `send_requests` باید هم در مانیفست اعلام شود و هم توسط کاربر در زبانهٔ مجوزها اعطا شود.

**توابع `sdk.api.register` از فرانت‌اند قابل فراخوانی نیستند:** بک‌اند باید فعال باشد (نه صرفاً نصب‌شده). نام تابع باید دقیقاً با آنچه فرانت‌اند به `sdk.backend.call` می‌دهد مطابقت داشته باشد (حساس به بزرگی و کوچکی حروف).

**هشدارهای سازگاری به‌صورت خطا نمایش داده می‌شوند:** این هشدارها مانع اجرا نمی‌شوند، اما نشان‌دهندهٔ کمبود در پوشش API هستند. برای پوشش API به جدول‌های نگاشت SDK در بالا مراجعه کنید.
