Ana içeriğe geç

Web SDK

@opennotification/web — tarayıcılar ve PWA'lar. Import anında hiçbir şey çalışmaz, SSR sırasında import etmek güvenlidir; @opennotification/core'dan yalnızca tipler gelir, paketinize doğrulama kütüphanesi girmez.

Bu çalışmadan önce HTTPS, manifest, VAPID çifti ve CORS_ORIGINS'te origin'iniz gerekir: Web platform kurulumu.

1 Kur

bun add @opennotification/web

ya da doğrudan CDN'den:

<script type="module">
import { init } from "https://cdn.jsdelivr.net/npm/@opennotification/web/+esm";
</script>

2 Service worker

Hazır derlenmiş paketi web kökünüze kopyalayın:

bun --filter @opennotification/web build:sw
cp packages/sdk-web/dist/sw.js public/sw.js

SDK onu /sw.js?api=<endpoint> olarak kaydeder — worker API taban URL'ini o query string'den okur, tek derleme her kuruluma uyar.

Zaten service worker'ınız mı var? Handler'ları içine alın:

// sw.ts
import { registerPushHandlers } from "@opennotification/web/sw";

registerPushHandlers({
apiUrl: "https://push.example.com",
defaults: { icon: "/icons/192.png", badge: "/icons/badge.png" },
});

Handler'lar şunları kapsar:

OlayYapar
pushBildirimi gösterir (title, body, icon, image, badge, tag, actions, silent) ve delivered bildirir.
notificationclickopened (gövde) ya da clicked (aksiyon) bildirir, yeni sekme açmadan önce hedef URL'deki mevcut sekmeye odaklanır.
notificationclosedismissed bildirir.
pushsubscriptionchangeYeniden abone olur ve /v1/subscriptions/rotate çağırır; aboneliğini sessizce yenileyen tarayıcı aboneye mal olmaz.

3 Başlat ve yeteneği kontrol et

import { init, mountInstallPrompt } from "@opennotification/web";

const on = init({
endpoint: "https://push.example.com",
appKey: "pk_live_…", // public anahtar
vapidKey: "BNcRd…", // uygulamanın VAPID public key'i
serviceWorkerPath: "/sw.js", // varsayılan
});

const cap = on.capability();
// { supported: true, reason: null, platform: "desktop" }
// { supported: false, reason: "IOS_NEEDS_INSTALL", platform: "ios" }
reasonAnlamıNe yapmalı
nullPush çalışır.Etkinleştir düğmenizi gösterin.
IOS_NEEDS_INSTALLiOS Safari sekmesi. Push yalnızca kurulu PWA'da var.Kurulum rehberini gösterin (aşağıda).
IOS_UNSUPPORTED_BROWSERiOS'ta Chrome/Firefox/Edge — kuramayan WebKit kabukları.Siteyi Safari'de açmalarını söyleyin.
INSECURE_CONTEXTHTTP üzerinden sunuluyor.Hosting'i düzeltin.
UNSUPPORTED_BROWSERService worker / Push API yok.Düğmeyi gizleyin.

iOS kurulum rehberi

const guidance = on.guidance("tr"); // "en" | "tr"
if (guidance?.actionable) mountInstallPrompt({ guidance });

guidance() Paylaş → Ana Ekrana Ekle adımlarını metin olarak döner; kendi sayfanızı yapmak istemiyorsanız mountInstallPrompt() küçük bir alt sayfa çizer. Kullanıcının düzeltemeyeceği nedenlerde (desteklenmeyen tarayıcı) actionable false'tur.

4 Abone ol — tıklamadan

document.querySelector("#enable")!.addEventListener("click", async () => {
const result = await on.subscribe({
externalId: "user_123",
tags: { plan: "premium" },
language: navigator.language,
});
if (!result.ok) {
switch (result.error.code) {
case "permission_denied": // bu origin için engelli — nasıl açılacağını gösterin
case "permission_dismissed": // istemi kapattı ya da hareket dışında çağrıldı
case "unsupported":
case "service_worker_failed":
case "push_subscribe_failed":
case "api_error":
case "network_error":
}
}
});

subscribe("user_123"), { externalId }'nin kısa hali. SDK worker'ı kaydeder, hazır olmasını bekler, izin ister, VAPID anahtarıyla abone olur ve aboneliği browser, standalone (PWA olarak kurulu), saat dilimi ve dille POST eder.

Yalnızca kullanıcı hareketi içinde

Bir tıklama/dokunma handler'ı dışında Notification.requestPermission() Safari'de sessizce reddedilir, Chrome'da giderek daha çok kısıtlanır. Bu olduğunda SDK permission_dismissed döner.

5 Kimlik, tag'ler, abonelikten çıkma

await on.login("user_456");
await on.setTags({ plan: "premium", streak: 42 });
await on.removeTags(["streak"]);
await on.setLanguage("tr");
await on.logout();
await on.unsubscribe(); // tarayıcıda abonelikten çıkar ve satırı siler

on.permission(); // "granted" | "denied" | "default" | "unsupported"
await on.isSubscribed();
on.subscriptionId(); // localStorage'dan

const stop = on.trackSessions(); // şimdi ve sekmeye her dönüşte oturum say
await on.trackSession(); // ya da bir kez kendiniz ping atın

Semantik: Kimlik. Oturumlar sunucuda tekilleştirilir (30 dakika boşluk kuralı). Sessiz (arka plan) kampanyalar tarayıcılara hiç ulaşmaz — fan-out web aboneliklerini atlar; hiçbir şey göstermeyen push aboneliği iptal ettirir.

Worker'ın aldığı yük

Referans olarak sunucunun her push'a şifrelediği:

{
"title": "Hafta sonu indirimi",
"body": "Pazar gecesine kadar her şeyde %30.",
"icon": "https://…/icon.png",
"image": "https://…/sale.jpg",
"badgeCount": 3,
"tag": "<collapseId>",
"actions": [{ "action": "shop", "title": "Alışverişe başla" }],
"data": { "msgId": "<imzalı>", "campaignId": "…", "url": "https://…/sale", "a:shop": "https://…/sale?cta=1", "screen": "sale" }
}

Buton hedefleri data["a:<id>"] olarak gider; tıklama handler'ı doğrusunu seçer. Kampanyanın sesi none ise silent: true eklenir; tag collapseId'den gelir, yeni push eskisini değiştirir.

Notlar

  • Hatalar Result olarak döner, asla fırlatılmaz.
  • Abonelik kimliği localStorage'da tutulur; site verisini temizlemek yeniden abone olmak demektir, bu da aynı endpoint'i upsert eder.
  • SDK'da VAPID private key'i okuyan ya da saklayan hiçbir şey yoktur — tarayıcıya yalnızca public olan ulaşır.