signalbird 2.5.0 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -36
- package/dist/angular.d.mts +4 -4
- package/dist/angular.d.ts +4 -4
- package/dist/angular.js +77 -19
- package/dist/angular.js.map +1 -1
- package/dist/angular.mjs +77 -19
- package/dist/angular.mjs.map +1 -1
- package/dist/app.d.mts +78 -53
- package/dist/app.d.ts +78 -53
- package/dist/app.js +76 -18
- package/dist/app.js.map +1 -1
- package/dist/app.mjs +76 -18
- package/dist/app.mjs.map +1 -1
- package/dist/browser.d.mts +1 -13
- package/dist/browser.d.ts +1 -13
- package/dist/browser.js +25 -3
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +25 -3
- package/dist/browser.mjs.map +1 -1
- package/dist/embed.d.mts +6 -6
- package/dist/embed.d.ts +6 -6
- package/dist/embed.js +1 -1
- package/dist/embed.js.map +1 -1
- package/dist/embed.mjs +1 -1
- package/dist/embed.mjs.map +1 -1
- package/dist/index.d.mts +61 -50
- package/dist/index.d.ts +61 -50
- package/dist/index.js +61 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +62 -24
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +2 -2
- package/dist/react-native.d.ts +2 -2
- package/dist/react-native.js +76 -18
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +76 -18
- package/dist/react-native.mjs.map +1 -1
- package/dist/react.d.mts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +76 -18
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +76 -18
- package/dist/react.mjs.map +1 -1
- package/dist/signalbird.js +20 -20
- package/dist/vue.d.mts +3 -3
- package/dist/vue.d.ts +3 -3
- package/dist/vue.js +76 -18
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +76 -18
- package/dist/vue.mjs.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -19,17 +19,17 @@ Bir seçenek daha var ve kod yazmaz: hazır sohbet widget'ı
|
|
|
19
19
|
| Dil / platform | Telsiz | Gönderim | Yönetim | Uygulama | Kurulum |
|
|
20
20
|
|---|:--:|:--:|:--:|:--:|---|
|
|
21
21
|
| Node.js / TypeScript | ✓ | ✓ | ✓ | ✓ | `npm i signalbird` |
|
|
22
|
-
| Tarayıcı (düz JS) | ✓ |
|
|
22
|
+
| Tarayıcı (düz JS) | ✓ | - | - | ✓ | `signalbird/browser` · `/app` |
|
|
23
23
|
| React / Next.js | ✓ | ✓ | ✓ | ✓ | `signalbird/react` |
|
|
24
|
-
| Vue 3 | ✓ |
|
|
25
|
-
| Angular | ✓ |
|
|
26
|
-
| React Native / Expo | ✓ |
|
|
27
|
-
| PHP / Laravel | ✓ | ✓ | ✓ |
|
|
28
|
-
| Python | ✓ | ✓ | ✓ |
|
|
29
|
-
| Go | ✓ | ✓ | ✓ |
|
|
30
|
-
| .NET / ASP.NET Core | ✓ | ✓ | ✓ |
|
|
31
|
-
| Swift (iOS) | ✓ |
|
|
32
|
-
| Kotlin (Android) | ✓ |
|
|
24
|
+
| Vue 3 | ✓ | - | - | ✓ | `signalbird/vue` |
|
|
25
|
+
| Angular | ✓ | - | - | ✓ | `signalbird/angular` |
|
|
26
|
+
| React Native / Expo | ✓ | - | - | ✓ | `signalbird/react-native` |
|
|
27
|
+
| PHP / Laravel | ✓ | ✓ | ✓ | - | `composer require pariette/signalbird` |
|
|
28
|
+
| Python | ✓ | ✓ | ✓ | - | `pip install signalbird` |
|
|
29
|
+
| Go | ✓ | ✓ | ✓ | - | `go get github.com/Pariette-Inc/signalbird.sdk` |
|
|
30
|
+
| .NET / ASP.NET Core | ✓ | ✓ | ✓ | - | `dotnet add package Signalbird.Sdk` |
|
|
31
|
+
| Swift (iOS) | ✓ | - | - | ✓ | SPM: `Signalbird` |
|
|
32
|
+
| Kotlin (Android) | ✓ | - | - | ✓ | `io.signalbird:signalbird-sdk` |
|
|
33
33
|
|
|
34
34
|
Metot adları diller arasında **birebir** aynıdır; her dil kendi yazım
|
|
35
35
|
geleneğini korur (`createRadioProject` / `create_radio_project` /
|
|
@@ -65,7 +65,7 @@ SIGNALBIRD_DOMAIN_KEY=sb_secret_live_…
|
|
|
65
65
|
Takım anahtarı (`sb_…`) her şeyi kapsar: e-posta, SMS, push, kişi ve kampanya,
|
|
66
66
|
sohbet, uygulama, domain, Telsiz log yazımı. Ne yapabileceğini anahtarın
|
|
67
67
|
kapsamları belirler; panelde üretilirken seçersiniz. **Adres yazmanız
|
|
68
|
-
gerekmez**
|
|
68
|
+
gerekmez** - üretim kökü paketin içindedir.
|
|
69
69
|
|
|
70
70
|
Ayrı anahtar isteğe bağlıdır: bir sunucunun yalnız log yazıp gönderim
|
|
71
71
|
yapamamasını istiyorsanız o sunucuya dar kapsamlı ikinci bir anahtar verirsiniz.
|
|
@@ -80,7 +80,7 @@ ve gizli olmadıkları için ayrı durmak zorundadırlar:
|
|
|
80
80
|
|
|
81
81
|
Gizli anahtar tarayıcıya **gömülemez**: sunucu, `Origin` başlığı taşıyan bir
|
|
82
82
|
istekte gizli anahtarı reddeder (`SECRET_KEY_IN_BROWSER`). Bu bir kolaylık
|
|
83
|
-
değil, kasıtlı bir duvardır
|
|
83
|
+
değil, kasıtlı bir duvardır - anahtar bir kez istemciye indiğinde herkesindir.
|
|
84
84
|
|
|
85
85
|
## Kurulum
|
|
86
86
|
|
|
@@ -94,10 +94,10 @@ değil, kasıtlı bir duvardır — anahtar bir kez istemciye indiğinde herkesi
|
|
|
94
94
|
| Go | `go get github.com/Pariette-Inc/signalbird.sdk` |
|
|
95
95
|
| .NET, ASP.NET Core | `dotnet add package Signalbird.Sdk` |
|
|
96
96
|
| Swift (iOS, macOS) | SPM: `https://github.com/Pariette-Inc/signalbird.sdk` |
|
|
97
|
-
| Kotlin (Android) | `implementation("io.signalbird:signalbird-sdk:2.
|
|
97
|
+
| Kotlin (Android) | `implementation("io.signalbird:signalbird-sdk:2.8.1")` |
|
|
98
98
|
| Canlı sohbet widget'ı (herhangi bir site) | `<script async src="https://signalbird.io/sdk/v1/signalbird.js" data-key="sb_public_live_…" data-channel="destek"></script>` |
|
|
99
99
|
|
|
100
|
-
> Hepsi **bu repodan** çıkar ve **aynı sürümü** taşır
|
|
100
|
+
> Hepsi **bu repodan** çıkar ve **aynı sürümü** taşır - ayrı SDK reposu ya da
|
|
101
101
|
> dil başına sürüm yoktur.
|
|
102
102
|
|
|
103
103
|
## Node.js / TypeScript
|
|
@@ -146,7 +146,7 @@ const result = await signalbird().batch([
|
|
|
146
146
|
### Next.js
|
|
147
147
|
|
|
148
148
|
Sunucu tarafında (route handler, server action, `app/api/**`) doğrudan
|
|
149
|
-
`signalbird` kullanılır. **İstemci bileşenlerinde kullanmayın**
|
|
149
|
+
`signalbird` kullanılır. **İstemci bileşenlerinde kullanmayın** - anahtar
|
|
150
150
|
paketle birlikte tarayıcıya iner.
|
|
151
151
|
|
|
152
152
|
```ts
|
|
@@ -183,7 +183,7 @@ sb.error('browser', 'sepet güncellenemedi', { cartId })
|
|
|
183
183
|
Kayıtlar tek tek değil, **toplu** gider (varsayılan 3 saniyede bir) ve sekme
|
|
184
184
|
kapanırken `sendBeacon` ile boşaltılır.
|
|
185
185
|
|
|
186
|
-
**React**
|
|
186
|
+
**React** - `app/providers.tsx` ya da `main.tsx`:
|
|
187
187
|
|
|
188
188
|
```tsx
|
|
189
189
|
useEffect(() => {
|
|
@@ -192,14 +192,14 @@ useEffect(() => {
|
|
|
192
192
|
}, [])
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
-
**Vue**
|
|
195
|
+
**Vue** - `main.ts`:
|
|
196
196
|
|
|
197
197
|
```ts
|
|
198
198
|
const sb = initSignalbird({ publicKey: import.meta.env.VITE_SIGNALBIRD_DOMAIN_KEY })
|
|
199
199
|
app.config.errorHandler = (err) => sb.error('browser', String(err))
|
|
200
200
|
```
|
|
201
201
|
|
|
202
|
-
**Angular**
|
|
202
|
+
**Angular** - `ErrorHandler` sağlayıcısı:
|
|
203
203
|
|
|
204
204
|
```ts
|
|
205
205
|
@Injectable()
|
|
@@ -232,7 +232,7 @@ SIGNALBIRD_DOMAIN_KEY=sb_secret_live_…
|
|
|
232
232
|
SIGNALBIRD_SOURCE=api-01
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
-
**Laravel'in kendi loglarını Telsiz'e bağlamak**
|
|
235
|
+
**Laravel'in kendi loglarını Telsiz'e bağlamak** - `config/logging.php`:
|
|
236
236
|
|
|
237
237
|
```php
|
|
238
238
|
'signalbird' => [
|
|
@@ -262,17 +262,26 @@ Signalbird::error('api', 'veritabanı bağlantısı koptu');
|
|
|
262
262
|
geçerli bir sebep değildir. Geliştirme sırasında `throwOnError: true`.
|
|
263
263
|
- **Tanımsız kanal düşürülmez.** İlk `log('odeme-hatasi', …)` çağrısında kanal
|
|
264
264
|
kendiliğinden açılır ve panelde "otomatik açıldı" işaretiyle görünür. Yeni
|
|
265
|
-
kanal **sessizdir**
|
|
265
|
+
kanal **sessizdir** - kuralı ekip koyar.
|
|
266
266
|
- **Seviye kanalın varsayılanını ezer.** `level` göndermezseniz kanalın kendi
|
|
267
267
|
seviyesi geçerlidir.
|
|
268
268
|
- **Kritik seviye sessiz saatleri deler.** Gece üçte ölen servis sabahı bekleyemez.
|
|
269
269
|
- **Tekrar bastırma kaydı değil bildirimi susturur.** Aynı mesaj kanalın
|
|
270
270
|
`dedupe` süresi içinde tekrar gelirse ikinci bildirim gitmez ama kayıt tutulur.
|
|
271
|
+
- **SDK sürümünü bildirir (2.6.0).** Her istek `X-Signalbird-Sdk:
|
|
272
|
+
<platform>/<sürüm>` taşır. Yeni sürüm çıktığında SDK süreç başına **bir kez**
|
|
273
|
+
uyarı yazar; eski sürümdeki anahtarların sahiplerine panel bildirimi gider.
|
|
274
|
+
Uyarı hata değildir, istek sonucu değişmez (CONTRACT §14).
|
|
275
|
+
- **Ziyaretçi kimliği doğrulanır (2.7.0).** Sohbet/push ziyaretçisinin
|
|
276
|
+
`external_id`'si ancak sunucunuzda üretilen `identity_hash` ile birlikte
|
|
277
|
+
gelirse güvenilir sayılır: kişi kaydına bağlama, cihaza push ve kanal
|
|
278
|
+
ajanının araçlarına giden güvenilir kimlik buna bağlıdır. Widget ayrıca
|
|
279
|
+
gerektiğinde Cloudflare Turnstile ister (CONTRACT §15).
|
|
271
280
|
|
|
272
281
|
## Gönderim (Messaging)
|
|
273
282
|
|
|
274
283
|
Takım API anahtarı (`sb_…`, panelde **Konsol → API anahtarları**, scope'lu)
|
|
275
|
-
ile çalışır. Telsiz anahtarı burada geçmez
|
|
284
|
+
ile çalışır. Telsiz anahtarı burada geçmez - istemci kurulurken
|
|
276
285
|
`WRONG_KEY_TYPE` ile reddeder. Yalnız sunucuda kullanılır.
|
|
277
286
|
|
|
278
287
|
Node:
|
|
@@ -370,7 +379,7 @@ import { management } from 'signalbird'
|
|
|
370
379
|
// Yeni ortam kurulumu: proje aç, kanalını tanımla, anahtarı sakla
|
|
371
380
|
const { data } = await management().createRadioProject({ name: 'ödeme-servisi' })
|
|
372
381
|
|
|
373
|
-
// `secret` YALNIZ burada döner
|
|
382
|
+
// `secret` YALNIZ burada döner - sunucuda yalnız özeti saklanır
|
|
374
383
|
await vault.write('SIGNALBIRD_DOMAIN_KEY', data!.secret)
|
|
375
384
|
|
|
376
385
|
await management().createRadioChannel(data!.project.id, {
|
|
@@ -405,7 +414,7 @@ const { data } = await management().embedToken({ module: 'chat' })
|
|
|
405
414
|
// data.url → 120 saniyelik, TEK KULLANIMLIK adres; doğrudan <iframe>'e verin
|
|
406
415
|
```
|
|
407
416
|
|
|
408
|
-
Anahtar `embed:issue` kapsamı ister
|
|
417
|
+
Anahtar `embed:issue` kapsamı ister - jeton 60 dakikalık bir panel oturumuna
|
|
409
418
|
çevrildiği için bu kapsam bilerek ayrıdır.
|
|
410
419
|
|
|
411
420
|
Aynısı PHP, Python, Go ve .NET'te birebir aynı metot adlarıyla:
|
|
@@ -428,7 +437,7 @@ await management.CreateRadioProjectAsync(new { name = "ödeme-servisi" });
|
|
|
428
437
|
|
|
429
438
|
Tam liste (40 metot): `docs/CONTRACT.md § 10`.
|
|
430
439
|
|
|
431
|
-
## Partner
|
|
440
|
+
## Partner - müşteri sağlama
|
|
432
441
|
|
|
433
442
|
Signalbird'ü kendi ürününüzün içinde satıyorsanız (sözleşmeli platform) bu yüzey
|
|
434
443
|
sizindir: müşteri hesabı açar, domain ekleyip izlemeye alır, uptime okur, ödeme
|
|
@@ -439,7 +448,7 @@ import { SignalbirdPartner } from 'signalbird'
|
|
|
439
448
|
|
|
440
449
|
const partner = new SignalbirdPartner({ domainKey: process.env.SIGNALBIRD_DOMAIN_KEY! })
|
|
441
450
|
|
|
442
|
-
// Müşteri açıldı
|
|
451
|
+
// Müşteri açıldı - idempotent: aynı external_id ikinci kez yeni hesap AÇMAZ
|
|
443
452
|
const { data } = await partner.createCompany({
|
|
444
453
|
external_id: 'sc_9911',
|
|
445
454
|
name: 'Acme',
|
|
@@ -465,7 +474,7 @@ const embed = await partner.createEmbedToken('sc_9911', {
|
|
|
465
474
|
})
|
|
466
475
|
// → <iframe src={embed.data.url} />
|
|
467
476
|
|
|
468
|
-
// Gönderilen her şeyin durumu
|
|
477
|
+
// Gönderilen her şeyin durumu - kendi panelinizde çizmek için (salt okur)
|
|
469
478
|
const log = await partner.listMessages('sc_9911', { channel: 'email', status: 'delivered' })
|
|
470
479
|
const one = await partner.getMessage('sc_9911', 'm_01J…') // olay zaman çizelgesi
|
|
471
480
|
const sum = await partner.messageSummary('sc_9911', '7d') // kanal bazlı özet
|
|
@@ -479,10 +488,10 @@ PHP'de `Signalbird::partner()->createCompany([...])`.
|
|
|
479
488
|
İki kural: **anahtar tarayıcıya inmez** ve **TXT'siz domain kampanya
|
|
480
489
|
gönderemez** (izleme, sohbet ve push açıktır). Ayrıntı: `docs/CONTRACT.md § 12`.
|
|
481
490
|
|
|
482
|
-
Mesaj uçları **salt okurdur**: alıcı maskeli döner, gövde hiç dönmez
|
|
491
|
+
Mesaj uçları **salt okurdur**: alıcı maskeli döner, gövde hiç dönmez - gövde
|
|
483
492
|
zaten saklanmıyor.
|
|
484
493
|
|
|
485
|
-
## Gönderim
|
|
494
|
+
## Gönderim - müşterinin kendi sisteminden
|
|
486
495
|
|
|
487
496
|
Bir platformun (SubmitCMS, veribenim…) müşterisiyseniz kendi sunucunuzdan da
|
|
488
497
|
gönderim yapabilirsiniz. Gereken tek şey **kendi takım anahtarınızdır**
|
|
@@ -537,7 +546,7 @@ istemiyorsanız ikincisi.
|
|
|
537
546
|
3. **Anahtar sunucuda kalır.** Tarayıcıya ya da mobil uygulamaya konmaz;
|
|
538
547
|
oralar için açık uygulama anahtarı (`sb_public_live_…`) vardır.
|
|
539
548
|
|
|
540
|
-
## Uygulama (App)
|
|
549
|
+
## Uygulama (App) - kendi sohbet arayüzünüz
|
|
541
550
|
|
|
542
551
|
Hazır widget yerine kendi arayüzünüzü yazmak, ya da sohbeti **mobil
|
|
543
552
|
uygulamanıza** koymak istiyorsanız bu yüzey içindir. Açık uygulama anahtarı
|
|
@@ -638,17 +647,49 @@ Signalbird.chat.open() // close() · toggle() · isOpen()
|
|
|
638
647
|
Signalbird.chat.on('unread', (n) => badge.textContent = n)
|
|
639
648
|
Signalbird.push.register({ token, platform: 'web', provider: 'fcm' })
|
|
640
649
|
Signalbird.destroy()
|
|
650
|
+
Signalbird.reset() // kullanıcı ÇIKIŞ yapınca (2.8.0, CONTRACT §15.3)
|
|
641
651
|
```
|
|
642
652
|
|
|
653
|
+
**Çıkışta `Signalbird.reset()` zorunlu (2.8.0).** Ziyaretçi sırrını, sohbet
|
|
654
|
+
geçmişini ve kimliği tarayıcıdan siler; aynı tarayıcıyı kullanan sonraki kişi
|
|
655
|
+
öncekinin sohbetini görmez, destek ajanı onu önceki kullanıcı sanmaz.
|
|
656
|
+
Sunucu da kimliği her oturumda yeniden imza ister.
|
|
657
|
+
|
|
643
658
|
`data-key`/`data-channel` yerine `Signalbird.init({ publicKey, chatKey, baseUrl?, locale? })` da
|
|
644
|
-
çağrılabilir.
|
|
645
|
-
|
|
659
|
+
çağrılabilir.
|
|
660
|
+
|
|
661
|
+
**Kimlik doğrulaması (2.7.0).** Oturum açmış kullanıcıyı tanıtırken
|
|
662
|
+
`external_id`'nin hash'ini SUNUCUNUZDA üretip birlikte verin; yoksa Signalbird
|
|
663
|
+
bu kimliği doğrulanmamış sayar (kişi kaydına bağlamaz, cihaza push hedeflemez,
|
|
664
|
+
ajan araçları kimliği yalnız `visitor.unverified` altında görür):
|
|
665
|
+
|
|
666
|
+
```php
|
|
667
|
+
// Blade - gizli anahtar sunucuda kalır
|
|
668
|
+
<script async src="https://signalbird.io/sdk/v1/signalbird.js"
|
|
669
|
+
data-key="sb_public_live_…" data-channel="destek"
|
|
670
|
+
data-external-id="{{ $user->id }}"
|
|
671
|
+
data-identity-hash="{{ Signalbird::identityHash((string) $user->id) }}"></script>
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
```js
|
|
675
|
+
Signalbird.identify({ external_id: 'user-1042', identityHash: '<sunucudan>', email: 'ali@example.com' })
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
`identity_hash = hex(HMAC-SHA256(hex(SHA-256(sb_secret_live_…)), external_id))`;
|
|
679
|
+
Node `client.identityHash(id)`, Python `client.identity_hash(id)`, Go
|
|
680
|
+
`client.IdentityHash(id)`, .NET `client.IdentityHash(id)`.
|
|
681
|
+
|
|
682
|
+
**Captcha.** Kanalda açıksa widget yeni ziyaretçide ve doğrulanmamış
|
|
683
|
+
ziyaretçinin ilk konuşmasında görünmez bir Cloudflare Turnstile jetonu alır;
|
|
684
|
+
betik yalnız panel ilk açıldığında yüklenir, etkileşim yalnız Cloudflare
|
|
685
|
+
isterse görünür. Kurulumda yapmanız gereken bir şey yoktur. Widget ev sahibi sayfaya asla hata fırlatmaz; Shadow DOM içinde
|
|
686
|
+
çalışır, sayfanızın CSS'iyle çakışmaz; < 40 KB gzip. Ayrıntı:
|
|
646
687
|
`docs/CONTRACT.md § 9` ve https://signalbird.io/sdk/widget.
|
|
647
688
|
|
|
648
|
-
## Gömme (embed)
|
|
689
|
+
## Gömme (embed) - Signalbird ekranını kendi panelinizde çalıştırın
|
|
649
690
|
|
|
650
691
|
Partner (veribenim, submitcms, yeni ortaklar) Signalbird modülünü kendi
|
|
651
|
-
panelinin içinde gösterir. Ekran kopyalanmaz
|
|
692
|
+
panelinin içinde gösterir. Ekran kopyalanmaz - **çalışan ekranın kendisi**
|
|
652
693
|
gelir; Signalbird'de güncellenen her şey partner panelinde de anında günceldir.
|
|
653
694
|
|
|
654
695
|
```html
|
|
@@ -693,7 +734,7 @@ Sunucu tarafı tek çağrıdır (`Signalbird::partner()->createEmbedToken(...)`,
|
|
|
693
734
|
| `CHANNEL_NOT_ALLOWED` | Tarayıcı anahtarı bu kanala yazamaz |
|
|
694
735
|
| `MODULE_DISABLED` | Paketinizde Telsiz (`logger`) modülü yok |
|
|
695
736
|
| `LIMIT_REACHED` | Aylık kayıt limitiniz doldu |
|
|
696
|
-
| `CHANNEL_DISABLED` | Kanal kapalı
|
|
737
|
+
| `CHANNEL_DISABLED` | Kanal kapalı - kayıt yazılmaz, kota da harcanmaz |
|
|
697
738
|
|
|
698
739
|
Gönderim ve Yönetim istemcilerine özgü: `WRONG_KEY_TYPE` (kurulumda),
|
|
699
740
|
`API_KEY_INVALID`, `API_KEY_SCOPE` (anahtarda gereken scope yok),
|
|
@@ -701,5 +742,6 @@ Gönderim ve Yönetim istemcilerine özgü: `WRONG_KEY_TYPE` (kurulumda),
|
|
|
701
742
|
`LIST_NOT_FOUND`, `MODULE_DISABLED`, `NETWORK_ERROR`, `TIMEOUT`, `HTTP_<durum>`.
|
|
702
743
|
|
|
703
744
|
Uygulama yüzeyi ve widget: `VISITOR_INVALID` (yerel kimlik silinir, yeni
|
|
704
|
-
oturum açılır), `CHAT_UNAVAILABLE` (kota
|
|
705
|
-
`NOT_INITIALIZED
|
|
745
|
+
oturum açılır), `CHAT_UNAVAILABLE` (kota - "sohbet kullanılamıyor" bandı),
|
|
746
|
+
`NOT_INITIALIZED`, `CAPTCHA_REQUIRED` / `CAPTCHA_INVALID` (403 - widget yeni
|
|
747
|
+
jetonla bir kez yeniden dener), `CONVERSATION_RATE_LIMITED` (429 - nazik bant).
|
package/dist/angular.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import { Observable } from 'rxjs';
|
|
|
2
2
|
import { SignalbirdApp, AppConfig, ChatState, SessionInput, IdentifyInput, RegisterDeviceInput } from './app.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* `signalbird/angular`
|
|
5
|
+
* `signalbird/angular` - Angular servisi ve sağlayıcısı.
|
|
6
6
|
*
|
|
7
7
|
* Dekoratör KULLANMAZ: `@Injectable()` yazsaydık paketin derlenmesi Angular
|
|
8
8
|
* sürümüne bağlanırdı ve her büyük sürümde yeniden yayın gerekirdi. Bunun
|
|
@@ -12,7 +12,7 @@ import { SignalbirdApp, AppConfig, ChatState, SessionInput, IdentifyInput, Regis
|
|
|
12
12
|
* RxJS bir `peerDependency`'dir (Angular zaten getirir).
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
/** DI belirteci
|
|
15
|
+
/** DI belirteci - Angular'ın `InjectionToken`'ına sarılır (aşağıda). */
|
|
16
16
|
declare const SIGNALBIRD_CONFIG = "SIGNALBIRD_CONFIG";
|
|
17
17
|
/**
|
|
18
18
|
* Uygulama başına tek örnek (`providedIn: 'root'` karşılığı).
|
|
@@ -27,7 +27,7 @@ declare class SignalbirdService {
|
|
|
27
27
|
constructor(config: AppConfig);
|
|
28
28
|
/** Sohbet durumu akışı. İlk abone olduğunda oturum başlar. */
|
|
29
29
|
chat$(): Observable<ChatState>;
|
|
30
|
-
/** Panel açık mı
|
|
30
|
+
/** Panel açık mı - yoklama hızını belirler. */
|
|
31
31
|
setOpen(open: boolean): void;
|
|
32
32
|
send(body: string, attachments?: unknown[]): Promise<unknown>;
|
|
33
33
|
typing(isTyping: boolean): void;
|
|
@@ -48,7 +48,7 @@ declare class SignalbirdService {
|
|
|
48
48
|
/**
|
|
49
49
|
* `bootstrapApplication(App, { providers: [provideSignalbird({ publicKey })] })`
|
|
50
50
|
*
|
|
51
|
-
* Dönen nesne Angular'ın `Provider` biçimindedir ama tipi buraya gömülmez
|
|
51
|
+
* Dönen nesne Angular'ın `Provider` biçimindedir ama tipi buraya gömülmez -
|
|
52
52
|
* paket Angular'a derleme zamanı bağımlılık taşımaz.
|
|
53
53
|
*/
|
|
54
54
|
declare function provideSignalbird(config: AppConfig): {
|
package/dist/angular.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Observable } from 'rxjs';
|
|
|
2
2
|
import { SignalbirdApp, AppConfig, ChatState, SessionInput, IdentifyInput, RegisterDeviceInput } from './app.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* `signalbird/angular`
|
|
5
|
+
* `signalbird/angular` - Angular servisi ve sağlayıcısı.
|
|
6
6
|
*
|
|
7
7
|
* Dekoratör KULLANMAZ: `@Injectable()` yazsaydık paketin derlenmesi Angular
|
|
8
8
|
* sürümüne bağlanırdı ve her büyük sürümde yeniden yayın gerekirdi. Bunun
|
|
@@ -12,7 +12,7 @@ import { SignalbirdApp, AppConfig, ChatState, SessionInput, IdentifyInput, Regis
|
|
|
12
12
|
* RxJS bir `peerDependency`'dir (Angular zaten getirir).
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
/** DI belirteci
|
|
15
|
+
/** DI belirteci - Angular'ın `InjectionToken`'ına sarılır (aşağıda). */
|
|
16
16
|
declare const SIGNALBIRD_CONFIG = "SIGNALBIRD_CONFIG";
|
|
17
17
|
/**
|
|
18
18
|
* Uygulama başına tek örnek (`providedIn: 'root'` karşılığı).
|
|
@@ -27,7 +27,7 @@ declare class SignalbirdService {
|
|
|
27
27
|
constructor(config: AppConfig);
|
|
28
28
|
/** Sohbet durumu akışı. İlk abone olduğunda oturum başlar. */
|
|
29
29
|
chat$(): Observable<ChatState>;
|
|
30
|
-
/** Panel açık mı
|
|
30
|
+
/** Panel açık mı - yoklama hızını belirler. */
|
|
31
31
|
setOpen(open: boolean): void;
|
|
32
32
|
send(body: string, attachments?: unknown[]): Promise<unknown>;
|
|
33
33
|
typing(isTyping: boolean): void;
|
|
@@ -48,7 +48,7 @@ declare class SignalbirdService {
|
|
|
48
48
|
/**
|
|
49
49
|
* `bootstrapApplication(App, { providers: [provideSignalbird({ publicKey })] })`
|
|
50
50
|
*
|
|
51
|
-
* Dönen nesne Angular'ın `Provider` biçimindedir ama tipi buraya gömülmez
|
|
51
|
+
* Dönen nesne Angular'ın `Provider` biçimindedir ama tipi buraya gömülmez -
|
|
52
52
|
* paket Angular'a derleme zamanı bağımlılık taşımaz.
|
|
53
53
|
*/
|
|
54
54
|
declare function provideSignalbird(config: AppConfig): {
|
package/dist/angular.js
CHANGED
|
@@ -4,6 +4,26 @@ var rxjs = require('rxjs');
|
|
|
4
4
|
|
|
5
5
|
// src/angular/index.ts
|
|
6
6
|
|
|
7
|
+
// src/shared/version.ts
|
|
8
|
+
var SDK_VERSION = "2.8.1" ;
|
|
9
|
+
var SDK_HEADER = "X-Signalbird-Sdk";
|
|
10
|
+
function sdkHeaderValue(platform) {
|
|
11
|
+
return `${platform}/${SDK_VERSION}`;
|
|
12
|
+
}
|
|
13
|
+
var warned = false;
|
|
14
|
+
function noteSdkStatus(headers) {
|
|
15
|
+
if (warned || !headers) return;
|
|
16
|
+
try {
|
|
17
|
+
const status = headers.get("Signalbird-Sdk-Status");
|
|
18
|
+
if (status !== "outdated" && status !== "unsupported") return;
|
|
19
|
+
warned = true;
|
|
20
|
+
const latest = headers.get("Signalbird-Sdk-Latest") ?? "?";
|
|
21
|
+
const message = status === "unsupported" ? `[signalbird] Bu SDK s\xFCr\xFCm\xFC (${SDK_VERSION}) art\u0131k desteklenmiyor. Son s\xFCr\xFCm: ${latest}. Paketi g\xFCncelleyin.` : `[signalbird] Yeni SDK s\xFCr\xFCm\xFC var: ${latest} (kurulu: ${SDK_VERSION}).`;
|
|
22
|
+
if (typeof console !== "undefined") console.warn(message);
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
7
27
|
// src/app/client.ts
|
|
8
28
|
var DEFAULT_BASE_URL = "https://live.signalbird.io/api";
|
|
9
29
|
var STORAGE_KEY = "sb_visitor";
|
|
@@ -53,9 +73,19 @@ var SignalbirdApp = class {
|
|
|
53
73
|
this.doFetch = config.fetchImpl ?? ((...args) => fetch(...args));
|
|
54
74
|
}
|
|
55
75
|
// ── Kimlik ────────────────────────────────────────────────────────────
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Uygulama ayarları: sohbet açık mı, renk, çalışma saati, ön-form.
|
|
78
|
+
*
|
|
79
|
+
* Oturum açmış kullanıcı biliniyorsa `external_id` + `identity_hash`
|
|
80
|
+
* verilir (CONTRACT §15.3): sunucu kimliği açılışta da doğrular. Kimliksiz
|
|
81
|
+
* açılış ziyaretçiye dokunmaz; çıkışta `signOut()` çağrılır.
|
|
82
|
+
*/
|
|
83
|
+
bootstrap(identity) {
|
|
84
|
+
const id = identity ? withIdentityHash(identity) : void 0;
|
|
85
|
+
return this.request("POST", "/v1/sdk/bootstrap", {
|
|
86
|
+
locale: this.config.locale,
|
|
87
|
+
...id?.external_id && id.identity_hash ? { external_id: id.external_id, identity_hash: id.identity_hash } : {}
|
|
88
|
+
});
|
|
59
89
|
}
|
|
60
90
|
/**
|
|
61
91
|
* Canlı bağlantı kanalı için imza.
|
|
@@ -74,7 +104,7 @@ var SignalbirdApp = class {
|
|
|
74
104
|
* derse yerel kimlik silinir ve bir sonraki çağrı yeni oturum açar.
|
|
75
105
|
*/
|
|
76
106
|
async startSession(input = {}) {
|
|
77
|
-
const result = await this.request("POST", "/v1/sdk/chat/session", input);
|
|
107
|
+
const result = await this.request("POST", "/v1/sdk/chat/session", withIdentityHash(input));
|
|
78
108
|
const visitor = result.data?.visitor;
|
|
79
109
|
if (result.ok && visitor?.id && visitor.secret) {
|
|
80
110
|
await this.storeVisitor({
|
|
@@ -89,9 +119,9 @@ var SignalbirdApp = class {
|
|
|
89
119
|
}
|
|
90
120
|
/** Oturum açmış kullanıcıyı ziyaretçiye bağlar (kişi kaydı upsert edilir). */
|
|
91
121
|
identify(input) {
|
|
92
|
-
return this.request("POST", "/v1/sdk/identify", input);
|
|
122
|
+
return this.request("POST", "/v1/sdk/identify", withIdentityHash(input));
|
|
93
123
|
}
|
|
94
|
-
/** Saklanan ziyaretçi kimliği
|
|
124
|
+
/** Saklanan ziyaretçi kimliği - yoksa `null`. */
|
|
95
125
|
async currentVisitor() {
|
|
96
126
|
const stored = await this.loadVisitor();
|
|
97
127
|
return stored ? { id: stored.id, name: stored.name, email: stored.email } : null;
|
|
@@ -110,7 +140,7 @@ var SignalbirdApp = class {
|
|
|
110
140
|
return this.request("GET", `/v1/sdk/chat/conversations/${enc(id)}`, void 0, query);
|
|
111
141
|
}
|
|
112
142
|
/**
|
|
113
|
-
* İlk mesajla konuşma açar. Kota burada harcanır
|
|
143
|
+
* İlk mesajla konuşma açar. Kota burada harcanır - konuşma başına sayılır,
|
|
114
144
|
* mesaj başına değil.
|
|
115
145
|
*/
|
|
116
146
|
startConversation(input) {
|
|
@@ -184,25 +214,25 @@ var SignalbirdApp = class {
|
|
|
184
214
|
// ── Push ──────────────────────────────────────────────────────────────
|
|
185
215
|
/**
|
|
186
216
|
* Cihaz token'ını kaydeder. Token'ı almak (FCM/APNs/Web Push izni) ev
|
|
187
|
-
* sahibinin işidir; SDK yalnız iletir
|
|
217
|
+
* sahibinin işidir; SDK yalnız iletir - izin diyaloğunu kimin, ne zaman
|
|
188
218
|
* göstereceği ürün kararıdır, kütüphane kararı değil.
|
|
189
219
|
*/
|
|
190
220
|
registerDevice(input) {
|
|
191
|
-
return this.request("POST", "/v1/sdk/devices", input);
|
|
221
|
+
return this.request("POST", "/v1/sdk/devices", withIdentityHash(input));
|
|
192
222
|
}
|
|
193
223
|
/** Çıkışta çağrılır: kayıt silinmez, kapatılır (geçmiş korunur). */
|
|
194
224
|
unregisterDevice(token) {
|
|
195
225
|
return this.request("DELETE", `/v1/sdk/devices/${enc(token)}`);
|
|
196
226
|
}
|
|
197
227
|
/**
|
|
198
|
-
* Bildirime dokunuldu
|
|
228
|
+
* Bildirime dokunuldu - açılma damgası.
|
|
199
229
|
*
|
|
200
230
|
* Push'ta açılmayı YALNIZCA uygulama bilir: FCM/APNs "teslim ettim" der,
|
|
201
231
|
* "kullanıcı dokundu" demez. Bildirim yükündeki `data.sb_message_id`
|
|
202
232
|
* değerini buraya geri gönderin.
|
|
203
233
|
*
|
|
204
234
|
* ```ts
|
|
205
|
-
* // React Native / Expo
|
|
235
|
+
* // React Native / Expo - bildirime dokunma işleyicisinde
|
|
206
236
|
* const id = response.notification.request.content.data?.sb_message_id
|
|
207
237
|
* if (id) await sb.reportPushOpened(String(id))
|
|
208
238
|
* ```
|
|
@@ -219,7 +249,8 @@ var SignalbirdApp = class {
|
|
|
219
249
|
const isForm = typeof FormData !== "undefined" && body instanceof FormData;
|
|
220
250
|
const headers = {
|
|
221
251
|
Accept: "application/json",
|
|
222
|
-
"X-Signalbird-Key": this.config.publicKey
|
|
252
|
+
"X-Signalbird-Key": this.config.publicKey,
|
|
253
|
+
[SDK_HEADER]: sdkHeaderValue(appPlatform())
|
|
223
254
|
};
|
|
224
255
|
const moduleKey = path.startsWith("/v1/sdk/devices") || path.startsWith("/v1/sdk/push") ? this.config.pushKey : this.config.chatKey;
|
|
225
256
|
if (moduleKey) headers["X-Signalbird-Module-Key"] = moduleKey;
|
|
@@ -235,6 +266,7 @@ var SignalbirdApp = class {
|
|
|
235
266
|
body: body === void 0 ? void 0 : isForm ? body : JSON.stringify(body),
|
|
236
267
|
signal: controller.signal
|
|
237
268
|
});
|
|
269
|
+
noteSdkStatus(response.headers);
|
|
238
270
|
const text = await response.text();
|
|
239
271
|
let data = null;
|
|
240
272
|
try {
|
|
@@ -297,6 +329,11 @@ var SignalbirdApp = class {
|
|
|
297
329
|
}
|
|
298
330
|
}
|
|
299
331
|
};
|
|
332
|
+
function withIdentityHash(input) {
|
|
333
|
+
if (!input || input.identityHash === void 0) return input;
|
|
334
|
+
const { identityHash, ...rest } = input;
|
|
335
|
+
return { ...rest, identity_hash: rest.identity_hash ?? identityHash };
|
|
336
|
+
}
|
|
300
337
|
function enc(value) {
|
|
301
338
|
return encodeURIComponent(value);
|
|
302
339
|
}
|
|
@@ -310,6 +347,9 @@ function buildQuery(query) {
|
|
|
310
347
|
const encoded = params.toString();
|
|
311
348
|
return encoded ? `?${encoded}` : "";
|
|
312
349
|
}
|
|
350
|
+
function appPlatform() {
|
|
351
|
+
return typeof navigator !== "undefined" && navigator.product === "ReactNative" ? "react-native" : "app";
|
|
352
|
+
}
|
|
313
353
|
|
|
314
354
|
// src/shared/socket.ts
|
|
315
355
|
var BACKOFF = [1e3, 2e3, 5e3, 1e4, 3e4];
|
|
@@ -434,7 +474,7 @@ var Socket = class {
|
|
|
434
474
|
}
|
|
435
475
|
}
|
|
436
476
|
/**
|
|
437
|
-
* Olay yolla
|
|
477
|
+
* Olay yolla - ACK İSTEMEDEN.
|
|
438
478
|
*
|
|
439
479
|
* `subscribe`in sonucunu beklemek bir tur daha protokol yönetmek demekti;
|
|
440
480
|
* oysa sonucu zaten davranıştan görüyoruz: imza tutmadıysa yayın gelmez ve
|
|
@@ -499,6 +539,8 @@ var ChatSession = class {
|
|
|
499
539
|
* da düzenleme ekrana hiç yansımaz.
|
|
500
540
|
*/
|
|
501
541
|
this.forceFull = false;
|
|
542
|
+
/** Son gönderilen `typing(true)` zamanı; 0 = açık sinyal yok. */
|
|
543
|
+
this.lastTypingSent = 0;
|
|
502
544
|
this.active = options.active ?? false;
|
|
503
545
|
}
|
|
504
546
|
// ── Abonelik ──────────────────────────────────────────────────────────
|
|
@@ -533,7 +575,7 @@ var ChatSession = class {
|
|
|
533
575
|
this.patch({ loading: false });
|
|
534
576
|
this.schedule();
|
|
535
577
|
}
|
|
536
|
-
/** Panel açıldı/kapandı
|
|
578
|
+
/** Panel açıldı/kapandı - yoklama hızı buna göre değişir. */
|
|
537
579
|
setActive(active) {
|
|
538
580
|
if (this.active === active) return;
|
|
539
581
|
this.active = active;
|
|
@@ -548,7 +590,7 @@ var ChatSession = class {
|
|
|
548
590
|
* Konuşmayı bırakır; sonraki mesaj YENİ bir konuşma açar.
|
|
549
591
|
*
|
|
550
592
|
* Ekranın "yeni sohbet" düğmesi de bunu çağırır. Sunucuda hiçbir şey
|
|
551
|
-
* silinmez
|
|
593
|
+
* silinmez - yalnız bu oturumun neye baktığı değişir.
|
|
552
594
|
*/
|
|
553
595
|
reset() {
|
|
554
596
|
this.patch({ conversation: null, messages: [], unread: 0, agentTyping: false, errorCode: void 0 });
|
|
@@ -562,7 +604,7 @@ var ChatSession = class {
|
|
|
562
604
|
this.socket = null;
|
|
563
605
|
this.live = false;
|
|
564
606
|
}
|
|
565
|
-
/** Canlı bağlantı kurulu mu
|
|
607
|
+
/** Canlı bağlantı kurulu mu - arayüz isterse gösterir (zorunlu değil). */
|
|
566
608
|
get isLive() {
|
|
567
609
|
return this.live;
|
|
568
610
|
}
|
|
@@ -617,16 +659,32 @@ var ChatSession = class {
|
|
|
617
659
|
}
|
|
618
660
|
/**
|
|
619
661
|
* Ziyaretçinin konu seçimi. Konuşma AÇILDIKTAN sonra çağrılırsa etkisizdir:
|
|
620
|
-
* açılmış konuşmanın konusunu ajan panelden değiştirir
|
|
662
|
+
* açılmış konuşmanın konusunu ajan panelden değiştirir - ziyaretçiye kendi
|
|
621
663
|
* konuşmasını yeniden sınıflandırma yetkisi vermek, atamayı da bozardı.
|
|
622
664
|
*/
|
|
623
665
|
setTopic(slug) {
|
|
624
666
|
this.patch({ topic: slug });
|
|
625
667
|
}
|
|
626
|
-
/**
|
|
668
|
+
/**
|
|
669
|
+
* İlk tuşta `true`, 2.5 s hareketsizlikte `false` - çağıran zamanlar.
|
|
670
|
+
*
|
|
671
|
+
* SDK yine de kendini korur (18 Eyl 2026): `true` 4 saniyede bir kez gider,
|
|
672
|
+
* `false` yalnız açık bir `true` varsa. Bir entegrasyon her tuşta
|
|
673
|
+
* çağırdığında (Penyu mobil öyle yapıyordu) 40 harflik mesaj 40 istek
|
|
674
|
+
* oluyor ve sunucunun hız sınırı ikinci mesajı 429 ile düşürüyordu. Web
|
|
675
|
+
* widget'ındaki kuralın aynısı.
|
|
676
|
+
*/
|
|
627
677
|
typing(isTyping) {
|
|
628
678
|
const conversation = this.state.conversation;
|
|
629
679
|
if (!conversation) return;
|
|
680
|
+
const now = Date.now();
|
|
681
|
+
if (isTyping) {
|
|
682
|
+
if (now - this.lastTypingSent < 4e3) return;
|
|
683
|
+
this.lastTypingSent = now;
|
|
684
|
+
} else {
|
|
685
|
+
if (this.lastTypingSent === 0) return;
|
|
686
|
+
this.lastTypingSent = 0;
|
|
687
|
+
}
|
|
630
688
|
void this.app.setTyping(conversation.id, isTyping);
|
|
631
689
|
}
|
|
632
690
|
/** Görülen son mesaja kadar okundu işaretler. */
|
|
@@ -825,7 +883,7 @@ var SignalbirdService = class {
|
|
|
825
883
|
}
|
|
826
884
|
return this.subject.asObservable();
|
|
827
885
|
}
|
|
828
|
-
/** Panel açık mı
|
|
886
|
+
/** Panel açık mı - yoklama hızını belirler. */
|
|
829
887
|
setOpen(open) {
|
|
830
888
|
this.session.setActive(open);
|
|
831
889
|
}
|