Nuvaka › Geliştirici belgeleri › Kavramlar

Kavramlar

Bir uzantının nerede çalıştığı, kim olduğunu nasıl kanıtladığı, izinlerin nasıl sorulduğu ve verinin cihazlar arasında nasıl tutarlı kaldığı.

Yalıtım ve kimlik

Arayüz çerçevesi

Arayüz, uygulamanın açtığı kum havuzlu bir çerçevede çalışır: sandbox="allow-scripts allow-forms", aynı köken (same-origin) yoktur. Bunun sonuçları:

  • localStorage, sessionStorage, IndexedDB ve çerez yoktur. Kalıcı veri için nuvaka.storage kullanılır.
  • allow-modals verilmediği için alert(), confirm() ve prompt() çalışmaz; soruları sayfanın içinde göster.
  • Yanıt başlığındaki içerik güvenlik politikası (CSP):
    default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; media-src 'self' blob: data:; img-src 'self' data: blob:; connect-src 'none'; frame-src 'none'; form-action 'none'
    Yani betikler yalnız paketin içinden yüklenir (satır içi <script> ve uzak betik yok), fetch/XHR/WebSocket kapalıdır (ağ için nuvaka.net.fetch), satır içi stil serbesttir, WebAssembly çalışır.
  • Dosyalar doğrulanmış paketten sunulur. Çerçevenin adresi uygulamanın iç ayrıntısıdır ve platforma göre değişir; kodunda yalnız göreli yol kullan (style.css, img/logo.svg).
  • window.parent, top, opener ve document.cookie kullanımı paket taramasında reddedilir. Uygulamayla tek iletişim yolu nuvaka.*'dır.

Kimlik zinciri

Çerçeveyi uygulamanın güvenilir kabuğu açar ve ona özel bir MessageChannel portu bağlar. Kabuk bu porttan gelen her çağrıyı kendi bildiği uzantı kimliğiyle uygulamanın Rust katmanına iletir; uzantının gönderdiği herhangi bir kimlik yok sayılır. Rust tarafı uzantının kurulu ve açık olduğunu, izinleri ve sürümü kendi kayıtlarından doğrular.

Sunucu gerektiren her çağrıyı (depolama, notlar, bulut, mail…) uygulama, o uzantıya özel, 15 dakika geçerli bir uzantı token'ı ile yapar. Bu token yalnız uzantı uçlarında (/api/ext/v1/x/*) geçer ve yalnız kullanıcının verdiği sunucu izinlerini taşır. Kullanıcının oturum token'ı uzantıya hiçbir zaman verilmez, uzantı adına yapılan istekte de kullanılmaz. Kullanıcının oturumu kapatılırsa uzantı token'ı da geçersiz olur.

Hesap, şifre, 2FA, oturum, ödeme ve yönetici uçları hiçbir izinle açılmaz.

Arka plan

  • QuickJS motoru; her uzantı ayrı bir iş parçacığında, ayrı bir çalışma ortamında çalışır. Bellek sınırı 32 MB.
  • Kesintisiz çalışma dilimi 5 saniyedir: sonsuz döngü kesilir. Uzun işleri await ile parçala.
  • eval ve Function yoktur. Kod tek dosyalık bir ES modülüdür, import yapılamaz; birden çok dosyan varsa tek dosyada birleştir.
  • DOM ve fetch yoktur. setTimeout/setInterval, console.* (uygulama günlüğüne yazar), btoa/atob, TextEncoder/TextDecoder hazırdır.
  • Arka plan yalnız uygulama açıkken çalışır; uygulama kapalıyken hiçbir kod çalışmaz.

Tema

Kabuk temayı CSS değişkenleriyle verir; SDK bunları kök öğeye kendisi uygular, data-nv-theme="dark|light" özniteliğini ve color-scheme'ı ayarlar. Değişkenler: --nv-bg, --nv-surface, --nv-elevated, --nv-border, --nv-text, --nv-text-2, --nv-muted, --nv-accent, --nv-accent-contrast, --nv-success, --nv-warning, --nv-danger, --nv-radius, --nv-font. Değişiklik için nuvaka.ui.onTheme(fn).

body { background: var(--nv-bg, #0f1115); color: var(--nv-text, #e6e6e6); font-family: var(--nv-font, system-ui, sans-serif); }
button { border: 1px solid var(--nv-border, #333); border-radius: var(--nv-radius, 8px); }

İzinler ve risk sınıfları

Uzantı istediği her izni manifestte bir gerekçeyle (reason) yazar. Kurulum ekranı izinleri risk sınıfına göre renklendirir:

SınıfRenkÖrnekler
düşükyeşilnotifications, background, startup, nuvaka.push
ortasarınet, clipboard: write, nuvaka.friends, nuvaka.connections: list
yüksekturuncufiles, clipboard: read, nuvaka.notes, nuvaka.cloud: read, nuvaka.clipboard: read
kritikkırmızınuvaka.mail, nuvaka.cloud: write, nuvaka.connections: secrets

Kritik izin isteyen uzantıyı kurmak için kullanıcı ikinci bir onay verir ("Anladım: … kritik izinler istiyor"). Okuma yapan bir izin net ile birlikte istenirse uygulama "bu veriyi şu adreslere gönderebilir" diye ayrıca uyarır (tehlikeli ikililer).

Kullanıcı izinleri daha sonra geri alabilir. Kodun her çağrıda permission_required hatasını karşılamaya hazır olmalı. Bir güncelleme izin kümesini ya da net alan adlarını genişletirse otomatik güncelleme durur; kullanıcı onaylayana kadar eski sürüm çalışır.

Tam liste: İzin başvurusu.

Kritik izin onayı

Şu kapsamlar kurulumda verilse bile kalıcı değildir; her kullanımda kullanıcıya sorulur:

  • nuvaka.mail.read — mail klasörlerini, listesini ya da bir maili okumak
  • nuvaka.mail.send — kullanıcı adına mail göndermek (kime ve konu gösterilir)
  • nuvaka.connections.secrets — kayıtlı bir bağlantının şifresini/anahtarını okumak
  • nuvaka.cloud.write — Nuvaka dosyalarına yüklemek ya da silmek

Uygulama işlemin ayrıntısını gösteren bir pencere açar. Kullanıcı Yalnız bu sefer, 15 dakika ya da 1 saat seçebilir; kalıcı seçenek yoktur. Süreli onay o kapsam için süre bitene kadar sormadan geçer ve kullanıcı istediği an kapatabilir. Kullanıcı reddederse ya da en çok 2 dakika içinde karar vermezse çağrı permission_denied koduyla başarısız olur (SDK'da ConfirmationDeniedError). Bir uzantının aynı anda en çok 3 bekleyen onayı olabilir; fazlası confirmation_flood ile reddedilir.

try {
  await nuvaka.mail.send(accountId, { to: '[email protected]', subject: 'Rapor', body: 'Ekte.' })
} catch (e) {
  if (e.code === 'permission_denied') showInline('Gönderim onaylanmadı.')
  else if (e.code === 'permission_required') showInline('Mail gönderme izni verilmemiş.')
  else throw e
}

Ayrıca: her mail gönderimi ve her bağlantı şifresi okuma kullanıcının bildirim akışına düşer; mail gönderimi uzantı başına saatte 30 ile sınırlıdır.

Depolama, MVCC ve değişiklik olayları

Her uzantının sunucuda kendi anahtar-değer deposu vardır; izin gerekmez. Anahtar 1–200 karakterdir ve / içerebilir (summary/42); değer en çok 1 MB JSON'dur.

Her yazma okunan sürümü taşır

Depo MVCC ile çalışır: set ve delete okuduğun sürümü ister (yeni anahtar için 0). Sürüm sunucudakiyle tutmazsa, yani sen okuduktan sonra başka bir cihaz ya da arka plan yazdıysa, çağrı version_conflict hatası verir ve hata güncel sürümü ve değeri taşır. Sürüm vermezsen SDK çağrıyı göndermeden if_version_required ile reddeder.

const cur = await nuvaka.storage.get('settings')              // { value, version } | null
await nuvaka.storage.set('settings', { dark: true }, { version: cur ? cur.version : 0 })

Çoğu zaman storage.update yeterlidir: okur, işlevini eski değerle çağırır, okunan sürümle yazar; çakışmada güncel değerle en çok 5 kez yeniden dener. İşlev undefined dönerse hiçbir şey yazılmaz.

// Sayaç: iki cihaz aynı anda artırsa da hiçbir artış kaybolmaz
await nuvaka.storage.update('count', (n) => (n || 0) + 1)

// Yalnız gerektiğinde yaz
await nuvaka.storage.update('seen', (list = []) => list.includes(id) ? undefined : [...list, id])

Sürüm numaraları

Sürümler anahtar başına 1, 2, 3 diye gitmez: uzantının tüm verisi için ortak ve hep artan bir sıradan gelir. Silme de yeni bir sürüm alır; silinip yeniden oluşturulan anahtar her zaman daha büyük sürüm alır. Bu yüzden sürümü yalnız "okuduğum hâl" işareti olarak kullan, sayaç gibi yorumlama.

Değişiklik olayları

Her yazma ve silme kullanıcının tüm cihazlarına bir olay gönderir. SDK anahtar başına bildiği en büyük sürümü tutar ve yalnız daha yeni sürümleri iletir; gecikmiş ya da sırası karışmış bir olay eski değeri geri getiremez. Olay gelince SDK değeri kendisi okur:

const off = nuvaka.storage.onChanged((key, change) => {
  if (key === null) return resetAll()           // uzantının tüm verisi silindi
  // change: { value, version, deleted }
  render(key, change.deleted ? null : change.value)
})

Bir bağlamın (çerçeve ya da arka plan) kendi yazmaları ona geri gelmez. Aynı cihazdaki arka planın yazması arayüze, arayüzün yazması arka plana ve başka cihazların yazmaları her ikisine gelir.

Senkron

  • Kurulumlar hesaba bağlıdır: bir cihazda kurulan uzantı diğer cihazlarda indirilir, doğrulanır ve kurulur; kaldırma da eşitlenir. Kullanıcı bir uzantıyı tek cihazda ya da tüm cihazlarda durdurabilir.
  • Depo sunucudadır; her cihaz aynı veriyi görür. İzinler, ayarlar ve bildirim sınırı da cihazlar arası aynıdır.
  • Yerel klasör seçimleri (files) cihaza özeldir, eşitlenmez.
  • Arka plan her cihazda ayrı çalışır. Uygulama açık olan her cihaz kendi zamanlamasını tetikler; iki cihaz aynı işi aynı anda yapabilir. Tek sefer yapılması gereken işleri MVCC ile sahiplen (bkz. GitHub takipçisi).
  • Kaçırılan bir zamanlama (uygulama kapalıyken) bir sonraki açılışta bir kez telafi edilir; günlük/haftalıkta yalnız sonuncusu.
  • Güncellemeler: kullanıcı uzantı başına otomatik, sor ya da kapalı seçer. İzni değişmeyen sürümler otomatik kurulabilir; önceki sürüm cihazda saklanır ve geri alınabilir.

Bildirim sınırı

Uzantı başına son 60 saniyede varsayılan en çok 3 bildirim gönderilebilir. Yerel bildirim (nuvaka.ui.notify) ile tüm cihazlara giden bildirim (nuvaka.push) aynı sayaçtan düşer. Sınır aşılınca uygulama kullanıcıya sınırı yükseltmek isteyip istemediğini sorar (dakikada 5, 10, 20 ya da 30):

  • Kullanıcı yükseltirse çağrı gönderilir; yeni sınır cihazlar arası geçerlidir.
  • "Hayır" derse 24 saat boyunca sorulmaz ve sınırı aşan çağrılar notify_limit hatası verir (SDK'da NotifyLimitError). Soru penceresi açıkken gelen bildirimler de bu hatayla düşer.

Kullanıcı sınırı Uygulamalar › Uygulamaları yönet'te uzantının satırından dakikada 1–60 arasında değiştirebilir. Kodun bu hatayı yakalayıp işini sürdürmeli:

try {
  await nuvaka.push('Yeni sürüm', 'tauri v2.1.0')
} catch (e) {
  if (e.code !== 'notify_limit') throw e
  await nuvaka.storage.update('pending', (list = []) => [...list, 'tauri v2.1.0'])   // sonra yeniden dene
}

Yerel bildirimin başlığı "Uzantı adı · başlık" olarak gösterilir; başlık 100, gövde 500 karakterde kesilir. push başlığı zorunludur.

Depolama kotası

Manifestte "storage": { "quotaMB": N } ile 1–100 MB arası kota istenir; yazılmazsa 10 MB. Kota kullanıcı ve uzantı başınadır ve uzantının tüm verisini (anahtar-değer + dosya deposu) kapsar. Aşan yazma quota_exceeded hatası verir (SDK'da QuotaError).

Kullanıcı uzantıyı kaldırırken verisini 30 gün saklamayı seçebilir; bu sürede yeniden kurarsa veri geri gelir.

Hız sınırı ve kayıt

Sunucu çağrıları uzantı başına dakikada 300 ile sınırlıdır (aşımda rate_limited). Her sunucu çağrısının özeti kaydedilir; kullanıcı bir uzantının ne yaptığını görebilir.

Nuvaka Apps API v1 · son güncelleme 2026-09-27