npmjs.com ↗
Kurulumsignalbird/app · /react · /vue · /angular · /react-native

Uygulama (App) - kendi sohbet arayüzünüz ve mobil push

Bu yüzey sizin müşterinizin kullanıcısı içindir: ziyaretçi ya da uygulama kullanıcısı. Canlı sohbet ve push cihaz kaydı yapar.

İki yolunuz var:

Hazır widget Uygulama SDK'sı
Kurulum tek <script> paket + kendi arayüzünüz
Görünüm panelden yönetilir tamamen sizin
Mobil yok iOS, Android, React Native
Ne zaman siteye hızlıca sohbet ürünün içine gömülü sohbet

Hazır widget için Widget dokümanına bakın. Bu sayfa SDK'yı anlatır.

Anahtar

Panelde Gelen Kutusu → Ayarlar → Uygulamalar (ya da SDK ile createApp) ile bir uygulama açın. Verilen sb_public_live_… anahtarı açıktır ve istemciye gömülür.

Güvenliği gizlilikten değil kısıttan gelir:

  • yalnız izinli kökenlerden çalışır (web),
  • yalnız ziyaretçinin kendi verisine dokunur,
  • gönderim yapamaz, kişi listesi okuyamaz.

Takım anahtarınızı (sb_…) istemciye koymayın. Kurucu bunu yakalar ve hata verir; yakalamasaydı bile bir kez yayınlanan anahtar herkesindir.

Ziyaretçi sırrı ve saklama

Kimlik iki parçadır: uygulama anahtarı ve ziyaretçi sırrı. Sır yalnız startSession yanıtında döner ve saklanması zorunludur - cihazda kalmazsa kullanıcı uygulamayı her açtığında sohbet geçmişini kaybeder.

Platform Varsayılan Nasıl değiştirilir
Web localStorage storage seçeneği
React Native yok - vermeniz gerekir asyncStorageAdapter(AsyncStorage)
iOS (Swift) UserDefaults SignalbirdStorage uyarlaması
Android (Kotlin) bellek (yalnız test) SharedPreferences sarmalayıcısı

Saklanan kayıt uygulama anahtarını da taşır. Anahtarı yenilerseniz eski kimlik otomatik yok sayılır ve yeni oturum açılır.


React / Next.js

bash
npm install signalbird
tsx
import { SignalbirdProvider, useChat, useIdentify } from 'signalbird/react'

export function App() {
  return (
    <SignalbirdProvider publicKey={process.env.NEXT_PUBLIC_SIGNALBIRD_APP_KEY!}>
      <Chat />
    </SignalbirdProvider>
  )
}

function Chat() {
  const {
    enabled,          // sohbet bu uygulamada açık mı (bootstrap cevabı)
    loading,
    messages,
    unread,
    agentTyping,
    withinHours,      // çalışma saati dışıysa false
    send,
    typing,
    markRead,
    close,
  } = useChat({ open: true })

  // Kullanıcı giriş yaptığında ziyaretçiyi kişi kaydına bağlar
  useIdentify(user && { external_id: user.id, email: user.email, name: user.name })

  if (!enabled) return null

  return (
    <>
      {!withinHours && <OfflineBanner />}
      {messages.map((m) => <Bubble key={m.id} message={m} />)}
      {agentTyping && <Typing />}
      <Composer onSend={send} onType={() => typing(true)} />
    </>
  )
}

open yalnız yoklama hızını değiştirir; paneli her açışta oturum yeniden kurulmaz. Rozet için sohbet arayüzü açılmadan da çalışan bir kısayol var:

tsx
import { useUnreadCount } from 'signalbird/react'

const unread = useUnreadCount()

Push kaydı:

tsx
import { usePushRegistration } from 'signalbird/react'

usePushRegistration(token ? { token, platform: 'web', provider: 'webpush' } : null)

Vue 3

ts
import { signalbirdPlugin, useChat } from 'signalbird/vue'

app.use(signalbirdPlugin, { publicKey: import.meta.env.VITE_SIGNALBIRD_APP_KEY })
vue
<script setup lang="ts">
import { ref } from 'vue'
import { useChat } from 'signalbird/vue'

const isOpen = ref(false)
const { state, send, typing, markRead } = useChat({ open: isOpen })
</script>

<template>
  <div v-for="m in state.messages" :key="m.id">{{ m.body }}</div>
  <span v-if="state.agentTyping">yazıyor…</span>
  <input @input="typing(true)" @keyup.enter="send(($event.target as HTMLInputElement).value)" />
</template>

Bileşen yok olduğunda yoklama otomatik durur.


Angular

ts
// main.ts
import { provideSignalbird } from 'signalbird/angular'

bootstrapApplication(App, {
  providers: [provideSignalbird({ publicKey: environment.signalbirdAppKey })],
})
ts
// chat.component.ts
import { SignalbirdService } from 'signalbird/angular'

@Component({
  template: `
    <div *ngFor="let m of (chat$ | async)?.messages">{{ m.body }}</div>
    <input #box (keyup.enter)="send(box.value)" />
  `,
})
export class ChatComponent implements OnInit {
  private signalbird = inject(SignalbirdService)

  chat$ = this.signalbird.chat$()

  ngOnInit() { this.signalbird.setOpen(true) }

  send(body: string) { this.signalbird.send(body) }
}

Paket Angular'a derleme zamanı bağımlılık taşımaz (dekoratör kullanmaz), bu yüzden Angular sürümünüzü yükselttiğinizde yeniden yayın beklemeniz gerekmez.


React Native / Expo

tsx
import AsyncStorage from '@react-native-async-storage/async-storage'
import { AppState } from 'react-native'
import {
  createSignalbirdApp,
  asyncStorageAdapter,
  useNativeChat,
  useNativePush,
} from 'signalbird/react-native'

// Depoyu vermek ZORUNLU
const client = createSignalbirdApp({
  publicKey: 'sb_public_live_…',
  storage: asyncStorageAdapter(AsyncStorage),
})

export function ChatScreen() {
  const [foreground, setForeground] = useState(true)

  useEffect(
    () => AppState.addEventListener('change', (s) => setForeground(s === 'active')).remove,
    [],
  )

  const { messages, send, agentTyping } = useNativeChat(client, {
    open: true,
    isForeground: foreground,   // arka planda yoklama turu atlanır - pil
  })

  useNativePush(client, token ? { token, platform: 'ios' } : null)

  return <MessageList data={messages} typing={agentTyping} onSend={send} />
}

Push token'ını almak (Expo Notifications ya da Firebase Messaging) ve izin diyaloğunu göstermek uygulamanın işidir: izni ne zaman isteyeceğiniz bir ürün kararıdır ve mağaza kuralları bunu ciddiye alır.


Swift (iOS)

Swift Package Manager: https://github.com/Pariette-Inc/signalbird.sdk

swift
import Signalbird

let client = try SignalbirdApp(config: .init(
    publicKey: "sb_public_live_…",
    chatKey: "destek",
    pushKey: "mobil"
))

// Sohbet açık mı, hangi renk, çalışma saati içinde miyiz
let boot = try await client.bootstrap()

try await client.startSession(["name": "Ayşe", "email": "ayse@example.com"])
try await client.startConversation(body: "Kargom nerede?")

// Yeni mesajlar - imleçle, tam listeyi tekrar indirmez
let updates = try await client.getConversation(conversationID, after: lastMessageID)

try await client.setTyping(conversationID: conversationID, isTyping: true)
try await client.markRead(conversationID: conversationID, lastMessageID: lastID)

// APNs
try await client.registerDevice(token: apnsToken, externalID: user.id, identityHash: user.signalbirdHash)

Keychain isteyen kendi deposunu verir:

swift
struct KeychainStorage: SignalbirdStorage {
    func get(_ key: String) -> String? { … }
    func set(_ key: String, _ value: String) { … }
    func remove(_ key: String) { … }
}

let client = try SignalbirdApp(config: .init(
    publicKey: "sb_public_live_…",
    chatKey: "destek",
    pushKey: "mobil",
    storage: KeychainStorage()
))

Kotlin (Android)

kotlin
implementation("io.signalbird:signalbird-sdk:2.10.1")
kotlin
import io.signalbird.sdk.*

class PrefsStorage(private val prefs: SharedPreferences) : SignalbirdStorage {
    override fun get(key: String) = prefs.getString(key, null)
    override fun set(key: String, value: String) = prefs.edit().putString(key, value).apply()
    override fun remove(key: String) = prefs.edit().remove(key).apply()
}

val client = SignalbirdApp(SignalbirdAppConfig(
    publicKey = "sb_public_live_…",
    chatKey = "destek",
    pushKey = "mobil",
    storage = PrefsStorage(prefs),
))

lifecycleScope.launch {
    client.bootstrap()
    client.startSession(mapOf("name" to "Ayşe"))
    client.startConversation("Kargom nerede?")

    val updates = client.getConversation(conversationId, after = lastMessageId)

    client.registerDevice(token = fcmToken, externalId = user.id, identityHash = user.signalbirdHash)
}

Tüm metotlar suspend'dir ve IO dağıtıcısında çalışır.


Çatısız kullanım (düz TypeScript)

typescript
import { SignalbirdApp, ChatSession } from 'signalbird/app'

const client = new SignalbirdApp({ publicKey: 'sb_public_live_…' })

// Ham uçlar
await client.bootstrap()
await client.startSession({ name: 'Ayşe' })
await client.startConversation({ body: 'Merhaba' })

// ya da durum katmanı
const session = new ChatSession(client, { active: true })

session.subscribe((state) => render(state))
await session.start()
await session.send('Kargom nerede?')

ChatSession şunları üstlenir: iyimser gönderim (mesaj listeye anında düşer, sunucu cevabıyla değiştirilir), yoklama merdiveni, okunmamış sayısı, yazıyor durumu.

Yoklama nasıl çalışır

WebSocket yoktur. İmleçli yoklama bağlantı kopmasında kendi kendini toparlar ve mobil ağda pil yakmaz.

Durum Aralık
Panel açık 3 sn
Panel kapalı - ilk 3 tur 20 sn
sonraki 2 tur 60 sn
sonrası 180 sn
Sekme/uygulama arka planda tur atlanır

Yeni veri geldiğinde merdiven sıfırlanır: konuşma canlandığında bir sonraki yoklamayı üç dakika beklemek, kullanıcıyı terk edilmiş hissettirirdi.

Kimlik doğrulaması (identity_hash)

Uygulama anahtarı açıktır; biri external_id'ye başkasının kimliğini yazabilir. Bu yüzden Signalbird external_id'yi (ve e-postayı) ancak yanında geçerli bir identity_hash varsa güvenilir sayar (2.7.0). Hash olmadan:

  • ziyaretçi kişi kaydınıza (contact) bağlanmaz,
  • cihaz o kullanıcıya push hedefi olarak bağlanmaz,
  • kanal ajanının araçları kimliği yalnız visitor.unverified altında görür.

Hash kendi sunucunuzda, gizli anahtarla üretilir ve oturum açan kullanıcıyla birlikte uygulamaya verilir (ör. giriş yanıtınızda):

text
identity_hash = hex( HMAC-SHA256( hex(SHA-256(sb_secret_live_…)), external_id ) )

Sunucu yardımcıları: PHP Signalbird::identityHash($id), Node client.identityHash(id), Python client.identity_hash(id), Go client.IdentityHash(id), .NET client.IdentityHash(id).

typescript
await client.startSession({ external_id: user.id, identity_hash: user.signalbirdHash })
await client.identify({ external_id: user.id, identity_hash: user.signalbirdHash, email: user.email })
await client.registerDevice({ token, platform: 'web', external_id: user.id, identity_hash: user.signalbirdHash })
// `identityHash` yazımı da kabul edilir; sunucuya `identity_hash` olarak gider.

Swift ve Kotlin'de sözlük/map girdisine "identity_hash" ekleyin; registerDevice(…, identityHash:) parametresi vardır.

Ziyaretçi nesnesi iki alan taşır: identity_verified (hash geçerliydi) ve verified (captcha geçti). Captcha yalnız hazır web widget'ında vardır; Origin taşımayan mobil istekler muaftır ve bu SDK jeton göndermez. Bootstrap yanıtındaki captcha alanı bilgi amaçlıdır.

Sürüm bildirimi

SDK her istekte sürümünü bildirir: X-Signalbird-Sdk: app/<sürüm> (React Native'de react-native/<sürüm>). Yeni bir sürüm yayınlandığında API yanıtında Signalbird-Sdk-Status: outdated (ya da artık desteklenmiyorsa unsupported) döner ve SDK süreç başına bir kez uyarı yazar (console.warn). Uyarı hata değildir: isteğin sonucu değişmez.

Panelde Domainler → [domain] → Anahtarlar her anahtarın hangi SDK sürümüyle kullanıldığını gösterir; eski sürümdeki anahtarlar için panelin tepesinde bir uyarı şeridi ve bildirim çıkar. Güncellemek için:

bash
npm i signalbird@latest

Hata davranışı

Hiçbir metot istisna fırlatmaz (kurucudaki anahtar denetimi hariç). Sonuç her zaman {ok, status, code?, message?} zarfıdır.

Kod Anlamı
VISITOR_INVALID Sır geçersiz - yerel kimlik silinir, sonraki çağrı yeni oturum açar
CHAT_UNAVAILABLE Kota doldu ya da sohbet kapalı
ORIGIN_NOT_ALLOWED Bu alan adı uygulamada tanımlı değil
MODULE_DISABLED Paketinizde chat ya da push modülü yok
NETWORK_ERROR / TIMEOUT Ağ (status 0)

Tam metot listesi (17 metot) ve davranış kuralları: signalbird.sdk/docs/CONTRACT.md § 11.