signalbird 1.4.0
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 +576 -0
- package/dist/angular.d.mts +53 -0
- package/dist/angular.d.ts +53 -0
- package/dist/angular.js +578 -0
- package/dist/angular.js.map +1 -0
- package/dist/angular.mjs +574 -0
- package/dist/angular.mjs.map +1 -0
- package/dist/app.d.mts +343 -0
- package/dist/app.d.ts +343 -0
- package/dist/app.js +518 -0
- package/dist/app.js.map +1 -0
- package/dist/app.mjs +514 -0
- package/dist/app.mjs.map +1 -0
- package/dist/browser.d.mts +56 -0
- package/dist/browser.d.ts +56 -0
- package/dist/browser.js +113 -0
- package/dist/browser.js.map +1 -0
- package/dist/browser.mjs +109 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/index.d.mts +1170 -0
- package/dist/index.d.ts +1170 -0
- package/dist/index.js +853 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +841 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react-native.d.mts +46 -0
- package/dist/react-native.d.ts +46 -0
- package/dist/react-native.js +576 -0
- package/dist/react-native.js.map +1 -0
- package/dist/react-native.mjs +569 -0
- package/dist/react-native.mjs.map +1 -0
- package/dist/react.d.mts +43 -0
- package/dist/react.d.ts +43 -0
- package/dist/react.js +587 -0
- package/dist/react.js.map +1 -0
- package/dist/react.mjs +580 -0
- package/dist/react.mjs.map +1 -0
- package/dist/signalbird.js +141 -0
- package/dist/vue.d.mts +46 -0
- package/dist/vue.d.ts +46 -0
- package/dist/vue.js +575 -0
- package/dist/vue.js.map +1 -0
- package/dist/vue.mjs +568 -0
- package/dist/vue.mjs.map +1 -0
- package/package.json +125 -0
package/README.md
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
# Signalbird SDK
|
|
2
|
+
|
|
3
|
+
**Tek paket, dört yüzey, on iki giriş noktası.** Panelde tıklayarak yapabildiğiniz her şey
|
|
4
|
+
kodla da yapılabilir.
|
|
5
|
+
|
|
6
|
+
| Yüzey | Ne yapar | Anahtar | Nerede |
|
|
7
|
+
|---|---|---|---|
|
|
8
|
+
| **Telsiz** (Radio) | projenizden bir **kanala** log/olay yazar | `sbr_live_…` / `sbr_pub_…` | sunucu / tarayıcı |
|
|
9
|
+
| **Gönderim** (Messaging) | e-posta, SMS, push gönderir; kişi, liste, kampanya yönetir; mesaj durumu okur; webhook imzası doğrular | `sb_…` | yalnız sunucu |
|
|
10
|
+
| **Yönetim** (Management) | Telsiz projesi/kanalı açar, olay akışını okur, **sohbet gelen kutusunu** işler, uygulama ve cihaz yönetir | `sb_…` + scope | yalnız sunucu |
|
|
11
|
+
| **Uygulama** (App) | müşterinizin **son kullanıcısına** canlı sohbet + push cihaz kaydı | `sbw_pub_…` | web, iOS, Android |
|
|
12
|
+
| **Partner** | Signalbird'ü kendi ürününde satan **sözleşmeli platform** müşterisini sağlar ve yetkilendirir | `sbp_live_…` | yalnız sunucu |
|
|
13
|
+
|
|
14
|
+
Bir seçenek daha var ve kod yazmaz: hazır sohbet widget'ı
|
|
15
|
+
(`signalbird.js`), siteye tek `<script>` ile gömülür.
|
|
16
|
+
|
|
17
|
+
### Dil matrisi
|
|
18
|
+
|
|
19
|
+
| Dil / platform | Telsiz | Gönderim | Yönetim | Uygulama | Kurulum |
|
|
20
|
+
|---|:--:|:--:|:--:|:--:|---|
|
|
21
|
+
| Node.js / TypeScript | ✓ | ✓ | ✓ | ✓ | `npm i signalbird` |
|
|
22
|
+
| Tarayıcı (düz JS) | ✓ | — | — | ✓ | `signalbird/browser` · `/app` |
|
|
23
|
+
| React / Next.js | ✓ | ✓ | ✓ | ✓ | `signalbird/react` |
|
|
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
|
+
|
|
34
|
+
Metot adları diller arasında **birebir** aynıdır; her dil kendi yazım
|
|
35
|
+
geleneğini korur (`createRadioProject` / `create_radio_project` /
|
|
36
|
+
`CreateRadioProject`). `node scripts/check-parity.mjs` bunu her derlemede
|
|
37
|
+
denetler.
|
|
38
|
+
|
|
39
|
+
Uygulama yüzeyi mobil ve tarayıcı içindir: gizli anahtar oraya gömülmez.
|
|
40
|
+
Gönderim ve Yönetim yüzeyleri yalnız sunucudadır.
|
|
41
|
+
|
|
42
|
+
## Telsiz
|
|
43
|
+
|
|
44
|
+
Telsiz'in tek işi vardır: projenizden bir **kanala** mesaj yazmak.
|
|
45
|
+
|
|
46
|
+
Bildirimin kime gideceği, hangi kanaldan (push/e-posta), sessiz saatlerde ne
|
|
47
|
+
olacağı ve aynı mesajın kaç kez uyarı üreteceği **sunucuda, kanal ayarlarında**
|
|
48
|
+
durur. Kod tarafında bunlar yoktur ve olmamalıdır: bildirim kuralını
|
|
49
|
+
değiştirmek için uygulamanızı yeniden yayınlamanız gerekmesin.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
proje → penyu.io (anahtarın sahibi)
|
|
53
|
+
kanal → critical, info, deploy… (bildirim kuralı burada)
|
|
54
|
+
olay → tek bir kayıt
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## İki anahtar, iki paket
|
|
58
|
+
|
|
59
|
+
| | Sunucu | Tarayıcı |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| Anahtar | `sbr_live_…` **gizli** | `sbr_pub_…` **açık** |
|
|
62
|
+
| Giriş noktası | `signalbird` · `pariette/signalbird` | `signalbird/browser` |
|
|
63
|
+
| Yazabildiği kanal | hepsi | yalnız izin verilenler |
|
|
64
|
+
| Kısıt | — | yalnız izinli alan adlarından |
|
|
65
|
+
|
|
66
|
+
Gizli anahtar tarayıcıya **gömülemez**: sunucu, `Origin` başlığı taşıyan bir
|
|
67
|
+
istekte gizli anahtarı reddeder (`SECRET_KEY_IN_BROWSER`). Bu bir kolaylık
|
|
68
|
+
değil, kasıtlı bir duvardır — anahtar bir kez istemciye indiğinde herkesindir.
|
|
69
|
+
|
|
70
|
+
## Kurulum
|
|
71
|
+
|
|
72
|
+
| Dil / çatı | Kurulum |
|
|
73
|
+
|---|---|
|
|
74
|
+
| Node.js, Next.js (sunucu), Express, NestJS, Fastify | `npm install signalbird` |
|
|
75
|
+
| React, Vue, Angular, Svelte, düz JS (tarayıcı) | `npm install signalbird` → `/browser`, `/app`, `/react`, `/vue`, `/angular` |
|
|
76
|
+
| React Native, Expo | `npm install signalbird` → `/react-native` |
|
|
77
|
+
| PHP, Laravel | `composer require pariette/signalbird` |
|
|
78
|
+
| Python (Django, FastAPI, Flask, Celery) | `pip install signalbird` |
|
|
79
|
+
| Go | `go get github.com/Pariette-Inc/signalbird.sdk` |
|
|
80
|
+
| .NET, ASP.NET Core | `dotnet add package Signalbird.Sdk` |
|
|
81
|
+
| Swift (iOS, macOS) | SPM: `https://github.com/Pariette-Inc/signalbird.sdk` |
|
|
82
|
+
| Kotlin (Android) | `implementation("io.signalbird:signalbird-sdk:1.2.0")` |
|
|
83
|
+
| Canlı sohbet widget'ı (herhangi bir site) | `<script async src="https://signalbird.io/sdk/v1/signalbird.js" data-app-key="sbw_pub_…"></script>` |
|
|
84
|
+
|
|
85
|
+
> Hepsi **bu repodan** çıkar ve **aynı sürümü** taşır — ayrı SDK reposu ya da
|
|
86
|
+
> dil başına sürüm yoktur.
|
|
87
|
+
|
|
88
|
+
## Node.js / TypeScript
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { signalbird } from 'signalbird'
|
|
92
|
+
|
|
93
|
+
// SIGNALBIRD_KEY ortam değişkeninden okunur
|
|
94
|
+
await signalbird().critical('critical', 'ödeme servisi yanıt vermiyor', {
|
|
95
|
+
service: 'iyzico',
|
|
96
|
+
attempt: 3,
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
await signalbird().info('info', 'ahmet@x.com yeni hesap oluşturdu')
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Kendi istemcinizi kurmak isterseniz:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { SignalbirdClient } from 'signalbird'
|
|
106
|
+
|
|
107
|
+
const sb = new SignalbirdClient({
|
|
108
|
+
apiKey: process.env.SIGNALBIRD_KEY!,
|
|
109
|
+
source: 'api-01', // hangi sunucudan geldiği
|
|
110
|
+
throwOnError: false, // üretimde kapalı kalmalı
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
await sb.log({ channel: 'deploy', message: 'v2.4.0 yayında', level: 'info' })
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Yakalanmamış hatalar:**
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
signalbird().captureUncaught('critical')
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Toplu gönderim** (kısmi başarı normaldir, satır satır sonuç döner):
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
const result = await signalbird().batch([
|
|
126
|
+
{ channel: 'info', message: 'iş 1 bitti' },
|
|
127
|
+
{ channel: 'info', message: 'iş 2 bitti' },
|
|
128
|
+
])
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Next.js
|
|
132
|
+
|
|
133
|
+
Sunucu tarafında (route handler, server action, `app/api/**`) doğrudan
|
|
134
|
+
`signalbird` kullanılır. **İstemci bileşenlerinde kullanmayın** — anahtar
|
|
135
|
+
paketle birlikte tarayıcıya iner.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
// app/api/webhook/route.ts
|
|
139
|
+
import { signalbird } from 'signalbird'
|
|
140
|
+
|
|
141
|
+
export async function POST(req: Request) {
|
|
142
|
+
try {
|
|
143
|
+
// …
|
|
144
|
+
} catch (error) {
|
|
145
|
+
await signalbird().error('webhook', (error as Error).message)
|
|
146
|
+
throw error
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Tarayıcı (React, Vue, Angular, düz JS)
|
|
152
|
+
|
|
153
|
+
Çatıya özel sarmalayıcı yoktur; gereken tek şey bir fonksiyon çağrısıdır.
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
// uygulama açılışında bir kez
|
|
157
|
+
import { initSignalbird } from 'signalbird/browser'
|
|
158
|
+
|
|
159
|
+
const sb = initSignalbird({
|
|
160
|
+
publicKey: 'sbr_pub_…',
|
|
161
|
+
source: 'web',
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
sb.captureErrors('browser') // window.onerror + unhandledrejection
|
|
165
|
+
sb.error('browser', 'sepet güncellenemedi', { cartId })
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Kayıtlar tek tek değil, **toplu** gider (varsayılan 3 saniyede bir) ve sekme
|
|
169
|
+
kapanırken `sendBeacon` ile boşaltılır.
|
|
170
|
+
|
|
171
|
+
**React** — `app/providers.tsx` ya da `main.tsx`:
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
const sb = initSignalbird({ publicKey: process.env.NEXT_PUBLIC_SIGNALBIRD_KEY! })
|
|
176
|
+
return sb.captureErrors()
|
|
177
|
+
}, [])
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Vue** — `main.ts`:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
const sb = initSignalbird({ publicKey: import.meta.env.VITE_SIGNALBIRD_KEY })
|
|
184
|
+
app.config.errorHandler = (err) => sb.error('browser', String(err))
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Angular** — `ErrorHandler` sağlayıcısı:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
@Injectable()
|
|
191
|
+
export class SignalbirdErrorHandler implements ErrorHandler {
|
|
192
|
+
private sb = initSignalbird({ publicKey: environment.signalbirdKey })
|
|
193
|
+
handleError(error: unknown) { this.sb.error('browser', String(error)) }
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Panelde bu projenin **izinli kökenlerini** ve **izinli kanallarını** açmayı
|
|
198
|
+
unutmayın; ikisi de boşken tarayıcı anahtarı hiçbir şey yapamaz. Kritik
|
|
199
|
+
kanalları tarayıcıya açmayın: istemci kodu herkesin elindedir.
|
|
200
|
+
|
|
201
|
+
## PHP / Laravel
|
|
202
|
+
|
|
203
|
+
```php
|
|
204
|
+
use Signalbird\Sdk\Facades\Signalbird;
|
|
205
|
+
|
|
206
|
+
Signalbird::critical('critical', 'ödeme servisi yanıt vermiyor', [
|
|
207
|
+
'service' => 'iyzico',
|
|
208
|
+
]);
|
|
209
|
+
|
|
210
|
+
Signalbird::info('info', 'ahmet@x.com yeni hesap oluşturdu');
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`.env`:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
SIGNALBIRD_KEY=sbr_live_…
|
|
217
|
+
SIGNALBIRD_SOURCE=api-01
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Laravel'in kendi loglarını Telsiz'e bağlamak** — `config/logging.php`:
|
|
221
|
+
|
|
222
|
+
```php
|
|
223
|
+
'signalbird' => [
|
|
224
|
+
'driver' => 'monolog',
|
|
225
|
+
'handler' => \Signalbird\Sdk\SignalbirdLogHandler::class,
|
|
226
|
+
'with' => ['channel' => 'laravel'],
|
|
227
|
+
'level' => 'error',
|
|
228
|
+
],
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Sonra `LOG_STACK=single,signalbird`. Mevcut `Log::error()` satırlarınız olduğu
|
|
232
|
+
gibi çalışır; tek satır kod yazmadan Telsiz'e düşerler.
|
|
233
|
+
|
|
234
|
+
Laravel dışı PHP:
|
|
235
|
+
|
|
236
|
+
```php
|
|
237
|
+
use Signalbird\Sdk\Signalbird;
|
|
238
|
+
|
|
239
|
+
Signalbird::configure('sbr_live_…');
|
|
240
|
+
Signalbird::error('api', 'veritabanı bağlantısı koptu');
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Davranış kuralları
|
|
244
|
+
|
|
245
|
+
- **Sessiz hata varsayılandır.** Telsiz erişilemezse çağrı `ok: false` döner ve
|
|
246
|
+
uygulamanız çalışmaya devam eder. Log göndermek, ödeme akışını çökertmek için
|
|
247
|
+
geçerli bir sebep değildir. Geliştirme sırasında `throwOnError: true`.
|
|
248
|
+
- **Tanımsız kanal düşürülmez.** İlk `log('odeme-hatasi', …)` çağrısında kanal
|
|
249
|
+
kendiliğinden açılır ve panelde "otomatik açıldı" işaretiyle görünür. Yeni
|
|
250
|
+
kanal **sessizdir** — kuralı ekip koyar.
|
|
251
|
+
- **Seviye kanalın varsayılanını ezer.** `level` göndermezseniz kanalın kendi
|
|
252
|
+
seviyesi geçerlidir.
|
|
253
|
+
- **Kritik seviye sessiz saatleri deler.** Gece üçte ölen servis sabahı bekleyemez.
|
|
254
|
+
- **Tekrar bastırma kaydı değil bildirimi susturur.** Aynı mesaj kanalın
|
|
255
|
+
`dedupe` süresi içinde tekrar gelirse ikinci bildirim gitmez ama kayıt tutulur.
|
|
256
|
+
|
|
257
|
+
## Gönderim (Messaging)
|
|
258
|
+
|
|
259
|
+
Takım API anahtarı (`sb_…`, panelde **Konsol → API anahtarları**, scope'lu)
|
|
260
|
+
ile çalışır. Telsiz anahtarı burada geçmez — istemci kurulurken
|
|
261
|
+
`WRONG_KEY_TYPE` ile reddeder. Yalnız sunucuda kullanılır.
|
|
262
|
+
|
|
263
|
+
Node:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
import { SignalbirdMessaging } from 'signalbird'
|
|
267
|
+
|
|
268
|
+
const sb = new SignalbirdMessaging({ apiKey: process.env.SIGNALBIRD_MESSAGING_KEY! })
|
|
269
|
+
|
|
270
|
+
const r = await sb.sendEmail({
|
|
271
|
+
to: 'ali@example.com',
|
|
272
|
+
class: 'transactional', // zorunlu: transactional | commercial
|
|
273
|
+
subject: 'Siparişiniz yola çıktı',
|
|
274
|
+
body: '<p>Merhaba {{first_name}}…</p>',
|
|
275
|
+
})
|
|
276
|
+
if (!r.ok) console.error(r.code, r.message) // ok:false → code + message
|
|
277
|
+
|
|
278
|
+
await sb.sendSms({ to: '+905551112233', class: 'transactional', body: 'Kodunuz: 4821' })
|
|
279
|
+
await sb.sendPush({ to: 'external:user-1042', class: 'transactional', subject: 'Yeni mesaj', body: '…' })
|
|
280
|
+
|
|
281
|
+
// Kişi + liste + kampanya
|
|
282
|
+
const list = await sb.createContactList({ name: 'agustos-kampanya' })
|
|
283
|
+
await sb.bulkContacts({ // 1000'lik parçalara bölünür
|
|
284
|
+
list_id: list.data.id,
|
|
285
|
+
consent_source: 'offline',
|
|
286
|
+
contacts: [{ email: 'a@x.com', first_name: 'Ayşe', attributes: { external_ref: 'rcp_1' } }],
|
|
287
|
+
})
|
|
288
|
+
const c = await sb.createCampaign({
|
|
289
|
+
name: 'Ağustos', channel: 'email', list_id: list.data.id,
|
|
290
|
+
subject: 'Merhaba {{first_name}}', body: '…', external_ref: 'cc_42',
|
|
291
|
+
})
|
|
292
|
+
for await (const m of sb.iterateCampaignMessages(c.data.batch.id)) {
|
|
293
|
+
console.log(m.external_ref, m.status)
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
PHP / Laravel:
|
|
298
|
+
|
|
299
|
+
```php
|
|
300
|
+
use Signalbird\Sdk\Facades\Signalbird;
|
|
301
|
+
|
|
302
|
+
$r = Signalbird::messaging()->sendEmail([
|
|
303
|
+
'to' => 'ali@example.com', 'class' => 'transactional',
|
|
304
|
+
'subject' => 'Siparişiniz yola çıktı', 'body' => '<p>…</p>',
|
|
305
|
+
]);
|
|
306
|
+
if (! $r['ok']) { Log::warning($r['code'], $r); }
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
`.env`: `SIGNALBIRD_MESSAGING_KEY=sb_…` (isteğe bağlı `SIGNALBIRD_MESSAGING_URL`,
|
|
310
|
+
`SIGNALBIRD_MESSAGING_TIMEOUT`). Laravel dışı PHP:
|
|
311
|
+
`Signalbird::configureMessaging('sb_…')` ya da `new MessagingClient('sb_…')`.
|
|
312
|
+
|
|
313
|
+
Metot kümesi iki dilde aynıdır: `sendEmail` `sendSms` `previewSms` `sendPush` ·
|
|
314
|
+
`listContacts` `createContact` `updateContact` `deleteContact` `bulkContacts` ·
|
|
315
|
+
`listContactLists` `createContactList` `deleteContactList` · `listCampaigns`
|
|
316
|
+
`createCampaign` `getCampaign` `cancelCampaign` `listCampaignMessages`
|
|
317
|
+
`iterateCampaignMessages` · `listMessages` `getMessage`. Hepsi
|
|
318
|
+
`{ok, status, data?, code?, message?}` döner; `throwOnError: true` ile istisna
|
|
319
|
+
(`SignalbirdError` / `SignalbirdException`, `code` + `status` + `body` taşır).
|
|
320
|
+
|
|
321
|
+
**Webhook imzası** (`message.*`, `campaign.*` olayları):
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
import { verifyWebhook } from 'signalbird'
|
|
325
|
+
// Express: app.post('/hooks/signalbird', express.raw({ type: '*/*' }), (req, res) => {
|
|
326
|
+
if (!verifyWebhook(req.body, req.header('X-Signalbird-Signature'), process.env.SIGNALBIRD_WEBHOOK_SECRET!)) {
|
|
327
|
+
return res.status(401).end()
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
```php
|
|
332
|
+
use Signalbird\Sdk\Messaging\Webhook;
|
|
333
|
+
|
|
334
|
+
abort_unless(Webhook::verify($request->getContent(), $request->header('X-Signalbird-Signature'), config('services.signalbird.webhook_secret')), 401);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Doğrulama **ham gövde** üzerinde yapılır; JSON'u ayrıştırıp yeniden
|
|
338
|
+
serileştirmek imzayı bozar.
|
|
339
|
+
|
|
340
|
+
## Yönetim (Management)
|
|
341
|
+
|
|
342
|
+
Panelde tıklayarak yaptığınız her şeyi kodla yapar. Ortam kurulumunuz, CI
|
|
343
|
+
akışınız ya da kendi ajan arayüzünüz artık panel oturumu taklit etmek zorunda
|
|
344
|
+
değil.
|
|
345
|
+
|
|
346
|
+
**Bu bir admin yüzeyi değildir:** anahtar tek bir takıma bağlıdır ve yalnız o
|
|
347
|
+
takımın kayıtlarına dokunur. Kullanıcı, faturalama ve abonelik işlemleri SDK'da
|
|
348
|
+
yoktur.
|
|
349
|
+
|
|
350
|
+
Panelden `radio:*`, `chat:*`, `apps:*` scope'larıyla bir `sb_…` anahtarı açın.
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
import { management } from 'signalbird'
|
|
354
|
+
|
|
355
|
+
// Yeni ortam kurulumu: proje aç, kanalını tanımla, anahtarı sakla
|
|
356
|
+
const { data } = await management().createRadioProject({ name: 'ödeme-servisi' })
|
|
357
|
+
|
|
358
|
+
// `secret` YALNIZ burada döner — sunucuda yalnız özeti saklanır
|
|
359
|
+
await vault.write('SIGNALBIRD_KEY', data!.secret)
|
|
360
|
+
|
|
361
|
+
await management().createRadioChannel(data!.project.id, {
|
|
362
|
+
key: 'odeme',
|
|
363
|
+
name: 'Ödeme',
|
|
364
|
+
level: 'critical',
|
|
365
|
+
notify_push: true,
|
|
366
|
+
quiet_from: 0,
|
|
367
|
+
quiet_to: 7, // kritik seviye sessiz saatleri yine de deler
|
|
368
|
+
})
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Sohbet gelen kutusunu kendi botunuzla işleyin:
|
|
372
|
+
|
|
373
|
+
```ts
|
|
374
|
+
const inbox = await management().listConversations({ status: 'open', per_page: 20 })
|
|
375
|
+
|
|
376
|
+
for (const conversation of inbox.data?.data ?? []) {
|
|
377
|
+
await management().reply(conversation.id, {
|
|
378
|
+
body: 'Merhaba! Ekibimiz birkaç dakika içinde yanıtlayacak.',
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
// İç not: gelen kutusunda görünür, ziyaretçiye ASLA gitmez
|
|
382
|
+
await management().reply(conversation.id, { body: 'Bot yanıtladı', is_internal: true })
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Aynısı PHP, Python, Go ve .NET'te birebir aynı metot adlarıyla:
|
|
387
|
+
|
|
388
|
+
```php
|
|
389
|
+
Signalbird::management()->createRadioProject(['name' => 'ödeme-servisi']);
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
```python
|
|
393
|
+
signalbird.SignalbirdManagement(api_key=key).create_radio_project({"name": "ödeme-servisi"})
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
```go
|
|
397
|
+
admin.CreateRadioProject(ctx, map[string]any{"name": "ödeme-servisi"})
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
```csharp
|
|
401
|
+
await management.CreateRadioProjectAsync(new { name = "ödeme-servisi" });
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
Tam liste (40 metot): `docs/CONTRACT.md § 10`.
|
|
405
|
+
|
|
406
|
+
## Partner — müşteri sağlama
|
|
407
|
+
|
|
408
|
+
Signalbird'ü kendi ürününüzün içinde satıyorsanız (sözleşmeli platform) bu yüzey
|
|
409
|
+
sizindir: müşteri hesabı açar, domain ekleyip izlemeye alır, uptime okur, ödeme
|
|
410
|
+
alındığında modül açar ve panel ekranını kendi sayfanıza gömersiniz.
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
import { SignalbirdPartner } from 'signalbird'
|
|
414
|
+
|
|
415
|
+
const partner = new SignalbirdPartner({ apiKey: process.env.SIGNALBIRD_PARTNER_KEY! })
|
|
416
|
+
|
|
417
|
+
// Müşteri açıldı — idempotent: aynı external_id ikinci kez yeni hesap AÇMAZ
|
|
418
|
+
const { data } = await partner.createCompany({
|
|
419
|
+
external_id: 'sc_9911',
|
|
420
|
+
name: 'Acme',
|
|
421
|
+
owner: { email: 'sahip@acme.com', name: 'Acme Sahibi', external_id: 'u_88' },
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
// Domain açıldı → anında izlemeye girsin
|
|
425
|
+
await partner.addDomain('sc_9911', {
|
|
426
|
+
external_id: 'd_5',
|
|
427
|
+
domain: 'acme.com',
|
|
428
|
+
monitoring: { enabled: true, frequency: 5 },
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
// Ödeme alındı → modül açılsın
|
|
432
|
+
await partner.grantModule('sc_9911', { module: 'email', expires_at: '2027-08-20' })
|
|
433
|
+
|
|
434
|
+
// Kendi domain listesi ekranınızda uptime
|
|
435
|
+
const uptime = await partner.companyUptime('sc_9911', '7d')
|
|
436
|
+
|
|
437
|
+
// Sohbet ekranını kendi sayfanıza gömün (jetonu SUNUCUNUZ üretir)
|
|
438
|
+
const embed = await partner.createEmbedToken('sc_9911', {
|
|
439
|
+
user_external_id: 'u_88', module: 'chat', theme: 'dark',
|
|
440
|
+
})
|
|
441
|
+
// → <iframe src={embed.data.url} />
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
PHP'de `Signalbird::partner()->createCompany([...])`.
|
|
445
|
+
|
|
446
|
+
İki kural: **anahtar tarayıcıya inmez** ve **TXT'siz domain kampanya
|
|
447
|
+
gönderemez** (izleme, sohbet ve push açıktır). Ayrıntı: `docs/CONTRACT.md § 12`.
|
|
448
|
+
|
|
449
|
+
## Uygulama (App) — kendi sohbet arayüzünüz
|
|
450
|
+
|
|
451
|
+
Hazır widget yerine kendi arayüzünüzü yazmak, ya da sohbeti **mobil
|
|
452
|
+
uygulamanıza** koymak istiyorsanız bu yüzey içindir. Açık uygulama anahtarı
|
|
453
|
+
(`sbw_pub_…`) kullanır ve yalnız ziyaretçinin kendi verisine dokunur.
|
|
454
|
+
|
|
455
|
+
**React / Next.js**
|
|
456
|
+
|
|
457
|
+
```tsx
|
|
458
|
+
import { SignalbirdProvider, useChat } from 'signalbird/react'
|
|
459
|
+
|
|
460
|
+
export function App() {
|
|
461
|
+
return (
|
|
462
|
+
<SignalbirdProvider appKey={process.env.NEXT_PUBLIC_SIGNALBIRD_APP_KEY!}>
|
|
463
|
+
<Chat />
|
|
464
|
+
</SignalbirdProvider>
|
|
465
|
+
)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function Chat() {
|
|
469
|
+
const { messages, unread, agentTyping, send } = useChat({ open: true })
|
|
470
|
+
|
|
471
|
+
return (
|
|
472
|
+
<>
|
|
473
|
+
{messages.map((m) => <Bubble key={m.id} message={m} />)}
|
|
474
|
+
{agentTyping && <Typing />}
|
|
475
|
+
<Composer onSend={send} />
|
|
476
|
+
</>
|
|
477
|
+
)
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**Vue 3**
|
|
482
|
+
|
|
483
|
+
```ts
|
|
484
|
+
app.use(signalbirdPlugin, { appKey: import.meta.env.VITE_SIGNALBIRD_APP_KEY })
|
|
485
|
+
|
|
486
|
+
const { state, send } = useChat({ open: isOpen })
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
**Angular**
|
|
490
|
+
|
|
491
|
+
```ts
|
|
492
|
+
bootstrapApplication(App, { providers: [provideSignalbird({ appKey })] })
|
|
493
|
+
|
|
494
|
+
// bileşende
|
|
495
|
+
chat$ = inject(SignalbirdService).chat$()
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**React Native / Expo**
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
import AsyncStorage from '@react-native-async-storage/async-storage'
|
|
502
|
+
import { createSignalbirdApp, asyncStorageAdapter, useNativeChat } from 'signalbird/react-native'
|
|
503
|
+
|
|
504
|
+
// Depoyu vermek ZORUNLU: sır cihazda kalmazsa geçmiş her açılışta kaybolur
|
|
505
|
+
const client = createSignalbirdApp({ appKey, storage: asyncStorageAdapter(AsyncStorage) })
|
|
506
|
+
|
|
507
|
+
const { messages, send } = useNativeChat(client, { open: true, isForeground })
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**Swift (iOS)**
|
|
511
|
+
|
|
512
|
+
```swift
|
|
513
|
+
let client = try SignalbirdApp(config: .init(appKey: "sbw_pub_…"))
|
|
514
|
+
|
|
515
|
+
try await client.startSession(["name": "Ayşe"])
|
|
516
|
+
try await client.startConversation(body: "Kargom nerede?")
|
|
517
|
+
try await client.registerDevice(token: apnsToken)
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**Kotlin (Android)**
|
|
521
|
+
|
|
522
|
+
```kotlin
|
|
523
|
+
val client = SignalbirdApp(SignalbirdAppConfig(appKey = "sbw_pub_…", storage = prefsStorage))
|
|
524
|
+
|
|
525
|
+
client.startSession(mapOf("name" to "Ayşe"))
|
|
526
|
+
client.startConversation("Kargom nerede?")
|
|
527
|
+
client.registerDevice(token = fcmToken)
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
Tam liste (17 metot) ve yoklama merdiveni: `docs/CONTRACT.md § 11`.
|
|
531
|
+
|
|
532
|
+
## Widget (canlı sohbet)
|
|
533
|
+
|
|
534
|
+
Panelde **Gelen Kutusu → Ayarlar → Uygulamalar**'dan bir uygulama açın; verilen
|
|
535
|
+
`sbw_pub_…` anahtarını sitenize gömün:
|
|
536
|
+
|
|
537
|
+
```html
|
|
538
|
+
<script async src="https://signalbird.io/sdk/v1/signalbird.js" data-app-key="sbw_pub_…"></script>
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
Bu kadar. Sohbet modülü açıksa balon görünür; renk, konum, karşılama, ön-form,
|
|
542
|
+
çalışma saatleri panelden yönetilir. Programatik kullanım:
|
|
543
|
+
|
|
544
|
+
```js
|
|
545
|
+
Signalbird.identify({ external_id: 'user-1042', email: 'ali@example.com', name: 'Ali Veli' })
|
|
546
|
+
Signalbird.chat.open() // close() · toggle() · isOpen()
|
|
547
|
+
Signalbird.chat.on('unread', (n) => badge.textContent = n)
|
|
548
|
+
Signalbird.push.register({ token, platform: 'web', provider: 'fcm' })
|
|
549
|
+
Signalbird.destroy()
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
`data-app-key` yerine `Signalbird.init({ appKey, baseUrl?, locale? })` da
|
|
553
|
+
çağrılabilir. Widget ev sahibi sayfaya asla hata fırlatmaz; Shadow DOM içinde
|
|
554
|
+
çalışır, sayfanızın CSS'iyle çakışmaz; < 20 KB gzip. Ayrıntı:
|
|
555
|
+
`docs/CONTRACT.md § 9` ve https://signalbird.io/sdk/widget.
|
|
556
|
+
|
|
557
|
+
## Hata kodları
|
|
558
|
+
|
|
559
|
+
| Kod | Anlamı |
|
|
560
|
+
|---|---|
|
|
561
|
+
| `INVALID_KEY` | Anahtar yok, yanlış ya da proje pasif |
|
|
562
|
+
| `SECRET_KEY_IN_BROWSER` | Gizli anahtar tarayıcıdan kullanıldı |
|
|
563
|
+
| `ORIGIN_NOT_ALLOWED` | Tarayıcı anahtarı bu alan adına açık değil |
|
|
564
|
+
| `CHANNEL_NOT_ALLOWED` | Tarayıcı anahtarı bu kanala yazamaz |
|
|
565
|
+
| `MODULE_DISABLED` | Paketinizde Telsiz (`logger`) modülü yok |
|
|
566
|
+
| `LIMIT_REACHED` | Aylık kayıt limitiniz doldu |
|
|
567
|
+
| `CHANNEL_DISABLED` | Kanal kapalı — kayıt yazılmaz, kota da harcanmaz |
|
|
568
|
+
|
|
569
|
+
Gönderim ve Yönetim istemcilerine özgü: `WRONG_KEY_TYPE` (kurulumda),
|
|
570
|
+
`API_KEY_INVALID`, `API_KEY_SCOPE` (anahtarda gereken scope yok),
|
|
571
|
+
`VALIDATION_ERROR` (422), `NO_CONSENT`, `SUPPRESSED`, `NO_SENDING_DOMAIN`,
|
|
572
|
+
`LIST_NOT_FOUND`, `MODULE_DISABLED`, `NETWORK_ERROR`, `TIMEOUT`, `HTTP_<durum>`.
|
|
573
|
+
|
|
574
|
+
Uygulama yüzeyi ve widget: `VISITOR_INVALID` (yerel kimlik silinir, yeni
|
|
575
|
+
oturum açılır), `CHAT_UNAVAILABLE` (kota — "sohbet kullanılamıyor" bandı),
|
|
576
|
+
`NOT_INITIALIZED`.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { SignalbirdApp, AppConfig, ChatState, SessionInput, IdentifyInput, RegisterDeviceInput } from './app.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `signalbird/angular` — Angular servisi ve sağlayıcısı.
|
|
6
|
+
*
|
|
7
|
+
* Dekoratör KULLANMAZ: `@Injectable()` yazsaydık paketin derlenmesi Angular
|
|
8
|
+
* sürümüne bağlanırdı ve her büyük sürümde yeniden yayın gerekirdi. Bunun
|
|
9
|
+
* yerine düz sınıf + `provideSignalbird()` fabrikası veriyoruz; Angular'ın DI'ı
|
|
10
|
+
* bunu sorunsuz kabul eder ve sürümden bağımsızdır.
|
|
11
|
+
*
|
|
12
|
+
* RxJS bir `peerDependency`'dir (Angular zaten getirir).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** DI belirteci — Angular'ın `InjectionToken`'ına sarılır (aşağıda). */
|
|
16
|
+
declare const SIGNALBIRD_CONFIG = "SIGNALBIRD_CONFIG";
|
|
17
|
+
/**
|
|
18
|
+
* Uygulama başına tek örnek (`providedIn: 'root'` karşılığı).
|
|
19
|
+
*
|
|
20
|
+
* Sohbet durumu bir `Observable`'dır; şablon `| async` ile doğrudan bağlanır.
|
|
21
|
+
*/
|
|
22
|
+
declare class SignalbirdService {
|
|
23
|
+
readonly client: SignalbirdApp;
|
|
24
|
+
private readonly session;
|
|
25
|
+
private readonly subject;
|
|
26
|
+
private started;
|
|
27
|
+
constructor(config: AppConfig);
|
|
28
|
+
/** Sohbet durumu akışı. İlk abone olduğunda oturum başlar. */
|
|
29
|
+
chat$(): Observable<ChatState>;
|
|
30
|
+
/** Panel açık mı — yoklama hızını belirler. */
|
|
31
|
+
setOpen(open: boolean): void;
|
|
32
|
+
send(body: string, attachments?: unknown[]): Promise<unknown>;
|
|
33
|
+
typing(isTyping: boolean): void;
|
|
34
|
+
markRead(): Promise<void>;
|
|
35
|
+
closeConversation(rating?: number, comment?: string): Promise<void>;
|
|
36
|
+
openSession(input: SessionInput): Promise<unknown>;
|
|
37
|
+
identify(input: IdentifyInput): Promise<unknown>;
|
|
38
|
+
registerDevice(input: RegisterDeviceInput): Promise<unknown>;
|
|
39
|
+
/** Uygulama kapanırken ya da testte: yoklamayı durdurur. */
|
|
40
|
+
destroy(): void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* `bootstrapApplication(App, { providers: [provideSignalbird({ appKey })] })`
|
|
44
|
+
*
|
|
45
|
+
* Dönen nesne Angular'ın `Provider` biçimindedir ama tipi buraya gömülmez —
|
|
46
|
+
* paket Angular'a derleme zamanı bağımlılık taşımaz.
|
|
47
|
+
*/
|
|
48
|
+
declare function provideSignalbird(config: AppConfig): {
|
|
49
|
+
provide: typeof SignalbirdService;
|
|
50
|
+
useFactory: () => SignalbirdService;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export { SIGNALBIRD_CONFIG, SignalbirdService, provideSignalbird };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { SignalbirdApp, AppConfig, ChatState, SessionInput, IdentifyInput, RegisterDeviceInput } from './app.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `signalbird/angular` — Angular servisi ve sağlayıcısı.
|
|
6
|
+
*
|
|
7
|
+
* Dekoratör KULLANMAZ: `@Injectable()` yazsaydık paketin derlenmesi Angular
|
|
8
|
+
* sürümüne bağlanırdı ve her büyük sürümde yeniden yayın gerekirdi. Bunun
|
|
9
|
+
* yerine düz sınıf + `provideSignalbird()` fabrikası veriyoruz; Angular'ın DI'ı
|
|
10
|
+
* bunu sorunsuz kabul eder ve sürümden bağımsızdır.
|
|
11
|
+
*
|
|
12
|
+
* RxJS bir `peerDependency`'dir (Angular zaten getirir).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** DI belirteci — Angular'ın `InjectionToken`'ına sarılır (aşağıda). */
|
|
16
|
+
declare const SIGNALBIRD_CONFIG = "SIGNALBIRD_CONFIG";
|
|
17
|
+
/**
|
|
18
|
+
* Uygulama başına tek örnek (`providedIn: 'root'` karşılığı).
|
|
19
|
+
*
|
|
20
|
+
* Sohbet durumu bir `Observable`'dır; şablon `| async` ile doğrudan bağlanır.
|
|
21
|
+
*/
|
|
22
|
+
declare class SignalbirdService {
|
|
23
|
+
readonly client: SignalbirdApp;
|
|
24
|
+
private readonly session;
|
|
25
|
+
private readonly subject;
|
|
26
|
+
private started;
|
|
27
|
+
constructor(config: AppConfig);
|
|
28
|
+
/** Sohbet durumu akışı. İlk abone olduğunda oturum başlar. */
|
|
29
|
+
chat$(): Observable<ChatState>;
|
|
30
|
+
/** Panel açık mı — yoklama hızını belirler. */
|
|
31
|
+
setOpen(open: boolean): void;
|
|
32
|
+
send(body: string, attachments?: unknown[]): Promise<unknown>;
|
|
33
|
+
typing(isTyping: boolean): void;
|
|
34
|
+
markRead(): Promise<void>;
|
|
35
|
+
closeConversation(rating?: number, comment?: string): Promise<void>;
|
|
36
|
+
openSession(input: SessionInput): Promise<unknown>;
|
|
37
|
+
identify(input: IdentifyInput): Promise<unknown>;
|
|
38
|
+
registerDevice(input: RegisterDeviceInput): Promise<unknown>;
|
|
39
|
+
/** Uygulama kapanırken ya da testte: yoklamayı durdurur. */
|
|
40
|
+
destroy(): void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* `bootstrapApplication(App, { providers: [provideSignalbird({ appKey })] })`
|
|
44
|
+
*
|
|
45
|
+
* Dönen nesne Angular'ın `Provider` biçimindedir ama tipi buraya gömülmez —
|
|
46
|
+
* paket Angular'a derleme zamanı bağımlılık taşımaz.
|
|
47
|
+
*/
|
|
48
|
+
declare function provideSignalbird(config: AppConfig): {
|
|
49
|
+
provide: typeof SignalbirdService;
|
|
50
|
+
useFactory: () => SignalbirdService;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export { SIGNALBIRD_CONFIG, SignalbirdService, provideSignalbird };
|