> ## Documentation Index
> Fetch the complete documentation index at: https://docs.evox.wraithesports.app/llms.txt
> Use this file to discover all available pages before exploring further.

# İlk gerçek plugin

> Ayarlar, kalıcı depolama ve host-brokered ağ çağrısıyla tuşta hava durumu gösteren bir T1 plugin yazın.

Bu tutorial <a href="/sdk/quickstart">Hızlı başlangıç</a> şablonunu gerçek bir plugin'e dönüştürür: kullanıcı ayarından şehir okuyan, host-brokered HTTPS ile hava durumunu çeken ve tuşa yazan bir **Hava** aksiyonu.

Öğrenecekleriniz: manifest izin bildirimi (`network.fetch` host allowlist'i), binding ayarları (`settingsSchema` + `action.settingsChanged`), `client.networkFetch` ve fail-closed hata gösterimi.

<Warning>T1 sandbox değildir; örnek yine de tüm ağ erişimini bilinçli olarak host-brokered `network.fetch` üzerinden yapar. Böylece aynı kod, public T2 hedefine taşınabilir kalır.</Warning>

## 1. Manifest: izin ve aksiyon bildirin

`manifest.json` içinde `permissions` ve `actions` bölümlerini güncelleyin:

```json theme={null}
{
  "permissions": [
    { "name": "key.display" },
    { "name": "network.fetch", "hosts": ["wttr.in"], "methods": ["GET"] }
  ],
  "actions": [
    {
      "id": "weather",
      "name": "Hava",
      "description": "Ayarlı şehrin hava durumunu gösterir.",
      "controllers": ["Keypad"],
      "supportedInMultiActions": false,
      "settingsSchema": [
        { "key": "city", "type": "text", "label": "Şehir", "required": true }
      ]
    }
  ]
}
```

* `network.fetch` **manifest'te bildirilen HTTPS hostlarla** sınırlıdır; `wttr.in` dışına istek `CAPABILITY_DENIED` alır.
* `settingsSchema` alanı, kullanıcı aksiyonu tuşa atadığında uygulamanın ayar panelinde görünür.

## 2. Runtime: event → ayar → ağ → ekran

`runtime.mjs`:

```js theme={null}
import { EvoxPluginClient } from '@evoxapp/plugin-sdk';
import { createNodeProcessIpcPluginTransport } from '@evoxapp/plugin-sdk/node';

const client = new EvoxPluginClient(createNodeProcessIpcPluginTransport(), {
  sdkVersion: '0.1.0',
  onError: (error) => console.error('[sdk] ' + String(error?.message || error?.code || 'Bilinmeyen hata')),
});

async function renderWeather(context) {
  const bindingId = context.bindingInstanceId;
  try {
    const settings = await client.getSettings(bindingId);
    const city = String(settings?.city || '').trim();
    if (!city) {
      await client.setTitle(bindingId, 'Şehir seçin');
      return;
    }
    // Host-brokered HTTPS: yalnız manifest'teki host + method izinlidir.
    const result = await client.networkFetch({
      url: `https://wttr.in/${encodeURIComponent(city)}?format=%t`,
      method: 'GET',
    });
    const text = String(result?.body ?? result?.text ?? '').trim();
    await client.setTitle(bindingId, text ? `${city}\n${text}` : city);
  } catch (error) {
    console.error('[weather] ' + String(error?.message || error));
    await client.setTitle(bindingId, 'Hata');
    await client.showError(bindingId);
  }
}

client.on('action.willAppear', async (event) => {
  if (event.context?.actionId === 'weather') await renderWeather(event.context);
});

client.on('action.keyDown', async (event) => {
  if (event.context?.actionId === 'weather') await renderWeather(event.context);
});

client.on('action.settingsChanged', async (event) => {
  if (event.context?.actionId === 'weather') await renderWeather(event.context);
});

await client.start();
```

Sözleşme noktaları:

* **Ayar okuma:** `getSettings(bindingId)` binding'e özel kalıcı ayarı döner; kullanıcı ayarı değiştirince `action.settingsChanged` tetiklenir ve yeniden çizersiniz.
* **Ağ:** `networkFetch({ url, method })` host tarafından doğrulanır (HTTPS-only, host allowlist, bounded request/response). Yanıt gövdesi host adapter'ının döndürdüğü bounded değerdir; savunmacı okuyun.
* **Hata:** başarısızlıkta `showError` + kısa başlık; exception yutmayın, loglayın.

## 3. Deneyin

1. Geliştirici penceresinden projeyi **yeniden yükleyin** (manifest değiştiği için gerekiyorsa kaldırıp yeniden seçin).
2. **Tuşlar** ekranında **Hava** aksiyonunu bir tuşa atayın.
3. Tuşun ayar panelinde **Şehir** girin (örn. `Istanbul`). Tuş, `Istanbul\n+29°C` gibi güncellenir.
4. Tuşa basmak veriyi yeniler.

## Nereye gidebilirsiniz

* Sıcaklığı `storageSet` ile önbelleğe alıp `willAppear`'da anında göstermek (bkz. <a href="/sdk/events-reference">referans</a>: `storage.private`).
* Kadran (Knob) desteği: `controllers: ["Knob"]` + `action.dialRotate` ile şehirler arasında geçiş.
* Credential'lı API'ler: <a href="/sdk/capabilities">`network.fetchWithCredential`</a> — raw token plugin'e asla dönmez.

<Note>Bu proje T2 `sandbox-js` hedefine taşınabilir: aynı SDK yüzeyi Worker transportuyla çalışır. Public upload durumu için <a href="/sdk/distribution-status">Dağıtım durumu</a>.</Note>
