---
url: https://docs.ogmabox.com/tr/plugins/README.md
description: >-
  Backend mantığı, frontend panelleri, komutlar, izinler ve mağaza metaverisiyle
  Ogma eklentileri geliştirin, paketleyin, yükleyin, etkinleştirin ve dağıtın.
---

# Ogma eklenti sistemi {#ogma-plugin-system}

Ogma eklentileri, araca özel backend mantığı, frontend arayüz panelleri ve iş akışı adımları ekler. Eklentiler diskteki bir dizinden yerel olarak yüklenir, proje bazında etkinleştirilir ve korumalı bir ortamda çalışır.

Bu belge, eklenti yazarları için temel başvuru kaynağıdır.

En hızlı başlangıç için [Eklenti hızlı başlangıç kılavuzunu](/tr/plugins/quickstart) kullanın.

***

## Hızlı başlangıç {#quick-start}

### En küçük backend eklentisi {#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; bir paketleyici kullanırken import ifadeleri kullanılabilir):

```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());
    }
  });
}
```

Bu, yalnızca backend içeren çalışan bir eklenti için yeterlidir. Kodu `backend/script.js` içinde tek dosya olarak tutun ve `manifest.json` içinde doğrudan bu dosyayı gösterin.

### Bir dakikalık derleme akışı (TypeScript kaynağı) {#one-minute-build-flow-typescript-source}

TypeScript yazıyorsanız şu yapıyı kullanın:

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

Derleme:

```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
```

Yükleme: **Eklentiler > Yükle** bölümünde `my-plugin/` dizinini seçin. Ardından eklentiyi etkinleştirin.

***

## Manifest başvurusu {#manifest-reference}

`manifest.json`, paketin kök dizininde bulunur. Tüm alanlar büyük/küçük harfe duyarlıdır.

### Üst düzey alanlar {#top-level-fields}

| Alan | Zorunlu | Tür | Notlar |
|-------|----------|------|-------|
| `id` | evet | string | Yalnızca küçük harfler, rakamlar ve kısa çizgiler. En fazla 64 karakter. Yüklü eklentiler arasında benzersiz olmalıdır. |
| `version` | evet | string | Semver: `MAJOR.MINOR.PATCH` |
| `name` | hayır | string | Arayüzde gösterilen ad. Varsayılanı `id` değeridir. |
| `description` | hayır | string | Tek satırlık özet. |
| `author` | hayır | object | `{ "name": "...", "email": "...", "url": "..." }` |
| `homepage` | hayır | string | Kaynak deposunun veya belgelerin URL'si. |
| `plugins` | evet | array | Bir veya daha fazla eklenti bileşeni kaydı (aşağıya bakın). |
| `permissions` | hayır | array | Gerekli izin adlarının listesi ([İzinler](#permissions) bölümüne bakın). |

### Eklenti bileşeni kaydı {#plugin-component-entry}

`plugins` dizisindeki her nesne bir bileşeni tanımlar.

**Backend bileşeni:**

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

**Frontend bileşeni:**

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

| Alan | Zorunlu | Notlar |
|-------|----------|-------|
| `kind` | evet | `"backend"` veya `"frontend"` |
| `id` | evet | Manifest içinde benzersizdir. Küçük harfler, kısa çizgiler. |
| `entrypoint` | evet | JS giriş dosyasının göreli yolu. |
| `style` | hayır | Eklenti iframe'inde yüklenen CSS dosyası. |
| `assets` | hayır | `/plugins/{id}/assets/` altında sunulan statik varlıkların dizini. |
| `backend.id` | hayır | `sdk.backend.*` RPC için bir frontend bileşenini backend bileşenine bağlar. |
| `runtime` | hayır (yalnızca backend) | `"javascript"` (varsayılan ve desteklenen tek değer). |

***

## Backend eklenti API'si (sdk) {#backend-plugin-api-sdk}

Backend `sdk` nesnesi `init(sdk)` işlevinize iletilir. `async` olarak işaretlenmedikçe tüm metotlar eşzamanlıdır.

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

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

Eklentinin günlük tamponuna yazar (Günlükler sekmesinde görünür). En fazla 500 kayıt tutulur. Her mesaj 1 KB'de kesilir.

### `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()`, eklentinin yazılabilir özel veri dizinini gösterir; örneğin `~/.local/share/ogma/plugins/my-plugin/data`. Dizin otomatik oluşturulur ve eklenti verilerini yeniden başlatmalar arasında saklamak için kullanılabilir.

Durum ve dosya yardımcıları için `sdk.storage`, `sdk.path` ve `sdk.fs` de kullanılabilir.

### `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`, eklenti kimliğiyle sınırlıdır ve eklenti yeniden başlatmaları arasında kalıcıdır.

### `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()` altındaki dosyalarla sınırlıdır.

`read` ve `write`, `readFile` ve `writeFile` için uyumluluk takma adları olarak korunur. Üzerine yazmak istemediğiniz bir dosyayı oluşturmadan önce `exists` veya `existsSync` kullanın. Bu API'ler eklenti çalışma ortamında eşzamanlı çalışır; tam Node.js `fs` modülü değildir. Eklentinin dosya erişimi `plugin_storage` iznini gerektirir ve eklentinin özel veri dizini içinde kalır. İş akışı JavaScript'inin dosya sistemi bağlamı farklıdır; [İş akışında dosya erişimi](../app/workflows.md#javascript-and-files) bölümüne bakın.

### `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 olayları için geri çağırma işlevleri kaydedin. Tüm geri çağırma işlevleri QuickJS korumalı alanında eşzamanlı olarak çağrılır.

```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` izninin manifestte bildirilmesini ve kullanıcı tarafından verilmesini gerektirir. [İzinler](#permissions) bölümüne bakın.

### `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` hız sınırları: dakikada 10, eklenti oturumu başına 500, olay geri çağırması başına 3.

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

Frontend'in `sdk.backend.*` üzerinden çağırabileceği backend RPC işlevleri kaydedin:

```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" });
```

İşleyici, frontend'den iletilen argümanları alır (ek bir `sdk` argümanı enjekte edilmez). Dönüş değerleri JSON olarak serileştirilip çağırana geri gönderilir.

Frontend bunları `sdk.backend.getScans(scanId)` üzerinden çağırır; [Frontend eklenti API'si](#frontend-plugin-api-sdk) bölümüne bakın.

`sdk.api.send`, olayları eklenti başına bir kuyruğa ekler (en fazla 200 kayıt). Frontend'ler bu kuyruğu `sdk.backend.onEvent` üzerinden sorgular.

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

Bunlar salt okunur sorgu ad alanlarıdır. Tam metot imzaları için [backend SDK başvurusuna](./backend-sdk.md) bakın.

### İstek sınıfları {#request-classes}

**`RequestSpecRaw`** — durdurulmuş bir isteği temsil eder. Bunu `onInterceptRequest` içinde alırsınız.

```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`** — salt okunur, yakalanmış bir istek (`sdk.requests.get` tarafından alınır).

```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`** — salt okunur, yakalanmış bir yanıt.

```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)
```

***

## Frontend eklenti API'si (sdk) {#frontend-plugin-api-sdk}

Frontend eklenti kodu, `/plugins/{id}/ui` adresinden yüklenen korumalı bir iframe içinde çalışır. Iframe, çağrıları backend'e ileten Ogma ana uygulamasıyla iletişim kurmak için `postMessage` kullanır.

SDK'ya `window.ogmaSDK` üzerinden erişilir. Ana uygulama köprüsü kurulduğunda canlı SDK'yı almak için `ogmaSDK.ready(cb)` çağırın:

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

Tüm SDK metotları Promise döndürür.

### `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` iznini gerektirir (otomatik verilir; kullanıcı onayı gerekmez).

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

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

`read_findings` iznini gerektirir (otomatik verilir).

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

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

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

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

### `sdk.backend` — backend RPC {#sdk-backend-backend-rpc}

Backend'de `sdk.api.register` ile kaydedilen işlevleri çağırın:

```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`, dahili olarak 2 saniyelik bir sorgulama döngüsü kullanır. Döndürülen abonelikten çıkma işlevini çağırarak dinlemeyi durdurun:

```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" });
```

Bir gezinme sayfası kaydeder. Şu anda ana uygulama tarafından alındığı onaylanır. Tam yönlendirici entegrasyonu geliştirme aşamasındadır.

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

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

Bir kenar çubuğu öğesi kaydeder. Şu anda eklenti arayüz paneliyle sınırlıdır; global kenar çubuğu bağlantısı geliştirme aşamasındadır.

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

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

Ana uygulama tarafından alındığı onaylanır. Komut paleti entegrasyonu geliştirme aşamasındadır.

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

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

Ana uygulama tarafından alındığı onaylanır. Bağlam menüsüne ekleme geliştirme aşamasındadır.

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

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

Eklenti panelinde geçici bir bildirim gösterir. Türler: `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
```

***

## İzinler {#permissions}

İzinleri `manifest.json` içinde bildirin:

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

### Otomatik verilen izinler (kullanıcı onayı gerekmez) {#auto-granted-permissions-no-user-approval-needed}

Bunlar her yüklü eklentiye her zaman verilir:

| İzin | İzin verdiği işlemler |
|------------|----------------|
| `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` |

### Korumalı izinler (kullanıcı onayı gerektirir) {#protected-permissions-require-user-approval}

Bunlar manifestte bildirilmeli ve İzinler sekmesinden kullanıcı tarafından açıkça verilmelidir:

| İzin | İzin verdiği işlemler |
|------------|----------------|
| `send_requests` | `sdk.requests.send` — dışarıya HTTP istekleri gönderme |
| `write_findings` | `sdk.findings.create`, `sdk.findings.update` |

Korumalı izinler bildiren bir eklenti etkinleştirilirken kullanıcıya bir onay istemi gösterilir. Kullanıcı İzinler sekmesinden istediği zaman izin verebilir veya izinleri geri alabilir.

***

## Eklenti paket yapısı {#plugin-package-structure}

Bir eklenti paketi yerel bir dizinden ve tarayıcı akışlarında `.zip` dışa aktarımlarından da yüklenebilir.

```
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 betiği gereksinimleri {#backend-script-requirements}

* Tek, kendi kendine yeterli bir JS dosyası olmalıdır.
* `require()` ve dinamik `import()` desteklenmez.
* Bir `init(sdk)` işlevini dışa aktarmalıdır (veya global olarak tanımlamalıdır).
* QuickJS tarafından desteklenen ES2020 alt kümesi: `async/await`, `Promise`, `Map`, `Set`, `Symbol`, `Proxy`, `Date`, `RegExp`, `JSON`. `fetch` ve `Buffer` yoktur.
* Desteklenen statik import ifadeleri eklenti ön işlemesiyle çözümlenir: `@ogma/sdk`, `crypto`, `fs`, `path`.
* En büyük dosya boyutu: 256 KB.

### Frontend betiği gereksinimleri {#frontend-script-requirements}

* Korumalı bir iframe içinde çalışır. Eklentinin `/plugins/{id}/api/*` adresine POST isteği gönderebilmesi ve `/plugins/{id}/events/poll` adresini sorgulayabilmesi için `connect-src: 'self'` izni vardır.
* CSP: `default-src 'none'; script-src 'nonce-...'; style-src 'self'; img-src data: blob: 'self'; connect-src 'self'`.
* Iframe korumalı alanında `allow-same-origin` yoktur; eklenti Ogma'nın üst DOM'una veya çerezlerine erişemez.
* SDK'ya erişmek için `ogmaSDK.ready(cb)` kullanın; geri çağırma çalışmadan SDK metotlarını çağırmayın.

***

## Ogma için eklenti derleme {#building-a-plugin-for-ogma}

Backend tek bir paketlenmiş JS dosyası olmak zorunda olduğundan TypeScript/ES modülü kaynak kodunu yüklemeden önce paketlemelisiniz.

Önerilen araç zinciri:

```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 geliştirme araç zincirini (`@caido-community/dev`) kullanıyorsanız `caido-dev build` çalıştırın ve ardından çıktıyı, kökünde `manifest.json` bulunan Ogma uyumlu bir düzene kopyalayın.

***

## Eklenti yükleme {#installing-a-plugin}

1. Sol kenar çubuğunda **Eklentiler** bölümünü açın.
2. Yüklü sekmesinin üst kısmındaki **Yükle** düğmesine tıklayın.
3. Masaüstü uygulamasında yerel klasör seçiciyi açmak için **Göz at** düğmesine tıklayın. Tarayıcıda, eklenti dizininin sunucu tarafındaki tam yolunu yazın.
4. Manifesti ve dosya envanterini kontrol etmek için **Doğrula** düğmesine tıklayın.
5. Doğrulama başarılıysa **Yükle** düğmesine tıklayın.
6. Listeden eklentiyi seçin ve **Etkinleştir** düğmesine tıklayın.
7. Eklenti korumalı izinler bildiriyorsa etkinleştirmeden önce **İzinler** sekmesinden bunları inceleyip verin.

***

## Sorun giderme {#troubleshooting}

**Eklentinin başlatılması sessizce başarısız oluyor:** **Günlükler** sekmesini kontrol edin. En yaygın nedenler:

* `sdk.meta.path()` çağrılmıştır ancak veri dizini oluşturulamamıştır.
* `init()` içinde işlenmemiş bir istisna vardır.
* Bir `sdk.*` çağrısı eksiktir veya yanlış yazılmıştır.

**Frontend boş görünüyor:** Tarayıcı konsolunda CSP ihlallerini kontrol edin. Frontend betiğinizin herhangi bir SDK metoduna erişmeden önce `ogmaSDK.ready(cb)` çağırdığından emin olun.

**`sdk.requests.send`, `Permission denied` hatası veriyor:** `send_requests` izni manifestte bildirilmeli VE İzinler sekmesinde kullanıcı tarafından verilmelidir.

**`sdk.api.register` işlevleri frontend'den çağrılamıyor:** Backend yalnızca yüklenmiş değil, etkinleştirilmiş olmalıdır. İşlev adı, frontend'in `sdk.backend.call` çağrısına ilettiği adla tam olarak eşleşmelidir (büyük/küçük harfe duyarlı).

**Uyumluluk uyarıları hata olarak görünüyor:** Bunlar çalışmayı engellemez ancak API kapsamındaki eksikleri gösterir. API kapsamı için yukarıdaki SDK eşleme tablolarına bakın.
