# iframe ve postMessage

> Tecof Studio’yu bir panel ya da uygulama içine iframe ile gömme — puck:* postMessage protokolü (kaydet, geri al, refetch, highlight, viewport), editörden gelen olaylar ve hostOrigin ile origin güvenliği.
>
> Kaynak: https://tecof-app-dev.vercel.app/editor-iframe · Bölüm: Tema geliştirme · Son güncelleme: 2018-10-20

Tecof paneli tema editörünü bir iframe içinde açar ve onunla `postMessage` üzerinden konuşur. Aynı protokolü kendi panelinizde ya da aracınızda kullanabilirsiniz. Mesaj tipleri geriye dönük uyumluluk için `puck:` önekini korur; bu, motorun Puck olduğu anlamına gelmez.

```mermaid
sequenceDiagram
    participant Host as Panel (üst pencere)
    participant Studio as Tecof Studio (iframe)
    Host->>Studio: puck:save
    Studio-->>Host: puck:saved { data }
    Host->>Studio: puck:viewport { width: "375px" }
    Studio-->>Host: puck:itemSelected { item: { type, id } }
    Host->>Studio: puck:refetch { highlightType }
```

## Üst pencere → editör

| Mesaj | Ek alanlar | Etki |
| :--- | :--- | :--- |
| `puck:save` | — | Taslağı kaydeder |
| `puck:publish` | — | Yalnız taslak kaydını tetikler; yayınlama panel/backend işidir |
| `puck:undo` / `puck:redo` | — | Geri al / yinele |
| `puck:refetch` | `highlightType?` | Taslağı sunucudan yeniden yükler (ör. bir AI ajanı taslağı sunucuda değiştirdiyse); verilirse o tipteki bileşen kanvasta vurgulanır |
| `puck:highlight` | `componentType` | Verilen tipteki bileşeni kanvasta vurgular |
| `puck:viewport` | `width` | `"375px"` / `375` → mobil, `"768px"` / `768` → tablet, diğer her değer → masaüstü |

```ts
const iframe = document.querySelector<HTMLIFrameElement>("#studio")!;
const EDITOR_ORIGIN = "https://tema.ornek.com";

iframe.contentWindow?.postMessage({ type: "puck:save" }, EDITOR_ORIGIN);
iframe.contentWindow?.postMessage({ type: "puck:viewport", width: "375px" }, EDITOR_ORIGIN);
```

## Editör → üst pencere

| Mesaj | Ek alanlar | Ne zaman |
| :--- | :--- | :--- |
| `puck:changed` | — | Doküman değişti (~300 ms debounce) |
| `puck:saved` | `data` (güncel taslak) | Kayıt başarılı |
| `puck:saveError` | `message` | Kayıt başarısız (revizyon önizlemesinde kaydetme denemesi dahil) |
| `puck:itemSelected` | `item: { type, id }` | Bir düğüm seçildi (Esc ile üst düğüme çıkıldığında da) |
| `puck:itemDeselected` | — | Seçim kaldırıldı |

```ts
window.addEventListener("message", (event) => {
  if (event.origin !== EDITOR_ORIGIN) return;
  switch (event.data?.type) {
    case "puck:changed":
      markDirty();
      break;
    case "puck:saved":
      markSaved(event.data.data);
      break;
    case "puck:saveError":
      showError(event.data.message);
      break;
    case "puck:itemSelected":
      showContextFor(event.data.item.type, event.data.item.id);
      break;
  }
});
```

Editör yalnız bir iframe içinde çalışırken mesaj gönderir; doğrudan açıldığında köprü sessizdir.

## Origin güvenliği

Gömülü kullanımda `hostOrigin` prop’unu **mutlaka** verin. Editör gelen mesajların `event.origin` değerini bununla karşılaştırır ve giden mesajları yalnız bu origin’e yollar. Prop verilmezse geriye uyumluluk için `'*'` kullanılır: her origin mesaj gönderebilir ve taslak verisi (`puck:saved`) her üst pencereye gider.

```tsx
<TecofEditor pageId={pageId} config={editorConfig} accessToken={token} hostOrigin="https://app.tecof.com" />
```

Kontrol listesi:

1. `hostOrigin` ile üst pencerenin origin’i birebir aynı olmalı (şema ve port dahil).
2. Mesajı `iframe.contentWindow`’a, hedef origin’i açıkça vererek gönderin.
3. Gelen mesajda `event.origin`’i ve `puck:` tipini doğrulayın.
4. Panel editöre JWT’yi adres parametresiyle verir (`?token=`); editör rotasını herkese açık bir sayfadan bağlamayın.
