signalbird 2.6.0 → 2.9.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/version.ts","../src/browser/index.ts"],"names":[],"mappings":"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","file":"browser.js","sourcesContent":["/**\n * SDK sürüm bildirimi - CONTRACT §14.\n *\n * Her istek `X-Signalbird-Sdk: <platform>/<sürüm>` taşır; API bunu kaydeder\n * ve yanıtta `Signalbird-Sdk-Status` (current | outdated | unsupported) ile\n * `Signalbird-Sdk-Latest` döner. SDK eski olduğunu öğrenince geliştiriciye\n * süreç başına BİR KEZ uyarı yazar. Uyarı hata değildir: istek sonucu\n * değişmez, istisna fırlatılmaz.\n *\n * Sürüm numarası derlemede `VERSION` dosyasından gömülür (tsup `define`).\n */\n\ndeclare const __SB_VERSION__: string;\n\nexport const SDK_VERSION: string = typeof __SB_VERSION__ === 'string' ? __SB_VERSION__ : '0.0.0';\n\nexport const SDK_HEADER = 'X-Signalbird-Sdk';\n\n/** `node/2.6.0` - platform adları CONTRACT §14.1'deki listededir. */\nexport function sdkHeaderValue(platform: string): string {\n return `${platform}/${SDK_VERSION}`;\n}\n\n/** Başlık okuyabilen her şey: fetch `Headers`, ya da sahte bir yanıt. */\ninterface HeaderSource {\n get(name: string): string | null;\n}\n\nlet warned = false;\n\n/**\n * Yanıttaki sürüm durumuna bakar; eskiyse bir kez `console.warn` yazar.\n * Hiçbir koşulda hata fırlatmaz: sürüm uyarısı yüzünden müşterinin isteği\n * bozulmamalı.\n */\nexport function noteSdkStatus(headers: HeaderSource | null | undefined): void {\n if (warned || !headers) return;\n\n try {\n const status = headers.get('Signalbird-Sdk-Status');\n\n if (status !== 'outdated' && status !== 'unsupported') return;\n\n warned = true;\n\n const latest = headers.get('Signalbird-Sdk-Latest') ?? '?';\n const message = status === 'unsupported'\n ? `[signalbird] Bu SDK sürümü (${SDK_VERSION}) artık desteklenmiyor. Son sürüm: ${latest}. Paketi güncelleyin.`\n : `[signalbird] Yeni SDK sürümü var: ${latest} (kurulu: ${SDK_VERSION}).`;\n\n if (typeof console !== 'undefined') console.warn(message);\n } catch {\n // uyarı yazılamadıysa sessiz kal\n }\n}\n\n/** Yalnız testler için: uyarıyı yeniden kurar. */\nexport function resetSdkStatusWarning(): void {\n warned = false;\n}\n","/**\n * signalbird/browser - tarayıcı istemcisi.\n *\n * Ayrı bir giriş noktası olmasının sebebi teknik değil, GÜVENLİKTİR: sunucu\n * anahtarı istemciye gömülemez ve sunucu `Origin` başlığı taşıyan bir istekte\n * onu zaten reddeder. Tarayıcı, açık anahtarı (`sb_public_live_…`) kullanır ve\n * güvenliği gizlilikten değil kısıttan gelir: yalnız izinli alan adlarından\n * çalışır ve Origin taşımayan istekte reddedilir (`ORIGIN_REQUIRED`).\n *\n * React, Vue, Angular ve düz JS aynı istemciyi kullanır; çatıya özel sarmalayıcı\n * yoktur çünkü gereken tek şey bir fonksiyon çağrısıdır.\n */\nimport { SDK_HEADER, noteSdkStatus, sdkHeaderValue } from '../shared/version';\n\nexport type Level = 'debug' | 'info' | 'warn' | 'error' | 'critical';\n\nexport interface BrowserConfig {\n /** Açık anahtar (`sb_public_live_…`). Gizli anahtar BURAYA YAZILMAZ. */\n publicKey: string;\n baseUrl?: string;\n source?: string;\n /**\n * Kayıtlar tek tek değil, toplu gider. Kullanıcının tarayıcısından saniyede\n * onlarca istek çıkarmak hem yavaş hem pahalıdır.\n */\n flushIntervalMs?: number;\n maxQueue?: number;\n debug?: boolean;\n}\n\ninterface QueuedEvent {\n key: string;\n message: string;\n level?: Level;\n context?: Record<string, unknown>;\n source?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://live.signalbird.io/api';\n\nexport class SignalbirdBrowser {\n private queue: QueuedEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly baseUrl: string;\n private readonly maxQueue: number;\n\n constructor(private readonly config: BrowserConfig) {\n if (!config.publicKey?.startsWith('sb_public_live_')) {\n throw new Error(\n 'Signalbird: tarayıcı istemcisi açık anahtar ister (sb_public_live_…). ' +\n 'Gizli anahtarı (sb_secret_live_…) istemci koduna KOYMAYIN.'\n );\n }\n\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.maxQueue = config.maxQueue ?? 50;\n\n if (typeof window !== 'undefined') {\n this.timer = setInterval(() => void this.flush(), config.flushIntervalMs ?? 3000);\n\n // Sekme kapanırken kuyruk boşaltılır. `sendBeacon` sayfa ölürken bile\n // gider; normal fetch yarıda kesilirdi.\n window.addEventListener('pagehide', () => this.flushBeacon());\n }\n }\n\n log(key: string, message: string, level?: Level, context?: Record<string, unknown>): void {\n this.queue.push({ key, message, level, context, source: this.config.source });\n\n // Kuyruk dolduysa beklemeden gönder: bellekte sonsuza kadar biriktirmek,\n // logu hiç göndermemekten kötüdür.\n if (this.queue.length >= this.maxQueue) {\n void this.flush();\n }\n }\n\n info(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'info', context);\n }\n\n warn(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'warn', context);\n }\n\n error(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'error', context);\n }\n\n /**\n * Tarayıcıdaki yakalanmamış hataları bağlar.\n *\n * Varsayılan anahtar `browser`dır ve KRİTİK DEĞİLDİR: istemci tarafı kod\n * herkesin elindedir, oradan kritik alarm tetiklemek kötü niyetli birine\n * ekibin telefonunu çaldırma imkânı verirdi. Hangi kanalın kime bildirim\n * göndereceği panelde durur; oradan sessiz bırakılabilir.\n */\n captureErrors(key = 'browser'): () => void {\n const onError = (event: ErrorEvent) => {\n this.error(key, event.message, {\n file: event.filename,\n line: event.lineno,\n column: event.colno,\n url: window.location.href,\n });\n };\n\n const onRejection = (event: PromiseRejectionEvent) => {\n this.error(key, String(event.reason), { url: window.location.href });\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onRejection);\n\n return () => {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onRejection);\n };\n }\n\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const batch = this.queue.splice(0, 100);\n\n try {\n const response = await fetch(`${this.baseUrl}/v1/radio/log/batch`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Signalbird-Key': this.config.publicKey,\n [SDK_HEADER]: sdkHeaderValue('browser'),\n },\n body: JSON.stringify({ events: batch }),\n keepalive: true,\n });\n noteSdkStatus(response.headers);\n } catch (error) {\n if (this.config.debug) {\n console.warn('[signalbird] gönderilemedi', error);\n }\n // Kayıtlar geri konur ama kuyruk sınırı aşılmaz: ağ uzun süre kapalıysa\n // sekme belleği şişmemeli.\n this.queue = [...batch, ...this.queue].slice(0, this.maxQueue);\n }\n }\n\n /** Sayfa kapanırken son gönderim. */\n private flushBeacon(): void {\n if (this.queue.length === 0 || typeof navigator === 'undefined') return;\n\n const blob = new Blob(\n [JSON.stringify({ events: this.queue.splice(0, 100) })],\n { type: 'application/json' }\n );\n\n // sendBeacon özel başlık taşıyamaz; anahtar ve SDK sürümü sorgu dizesinden gider.\n navigator.sendBeacon?.(\n `${this.baseUrl}/v1/radio/log/batch?k=${encodeURIComponent(this.config.publicKey)}` +\n `&sdk=${encodeURIComponent(sdkHeaderValue('browser'))}`,\n blob\n );\n }\n\n destroy(): void {\n if (this.timer) clearInterval(this.timer);\n void this.flush();\n }\n}\n\nlet singleton: SignalbirdBrowser | null = null;\n\n/** Uygulama başlangıcında bir kez çağrılır. */\nexport function initSignalbird(config: BrowserConfig): SignalbirdBrowser {\n singleton = new SignalbirdBrowser(config);\n return singleton;\n}\n\n/** Kurulmamışsa sessizce yok sayar - log çağrısı uygulamayı çökertmemeli. */\nexport function signalbird(): SignalbirdBrowser | null {\n return singleton;\n}\n"]}
1
+ {"version":3,"sources":["../src/shared/version.ts","../src/shared/serialize.ts","../src/browser/index.ts"],"names":[],"mappings":"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","file":"browser.js","sourcesContent":["/**\n * SDK sürüm bildirimi - CONTRACT §14.\n *\n * Her istek `X-Signalbird-Sdk: <platform>/<sürüm>` taşır; API bunu kaydeder\n * ve yanıtta `Signalbird-Sdk-Status` (current | outdated | unsupported) ile\n * `Signalbird-Sdk-Latest` döner. SDK eski olduğunu öğrenince geliştiriciye\n * süreç başına BİR KEZ uyarı yazar. Uyarı hata değildir: istek sonucu\n * değişmez, istisna fırlatılmaz.\n *\n * Sürüm numarası derlemede `VERSION` dosyasından gömülür (tsup `define`).\n */\n\ndeclare const __SB_VERSION__: string;\n\nexport const SDK_VERSION: string = typeof __SB_VERSION__ === 'string' ? __SB_VERSION__ : '0.0.0';\n\nexport const SDK_HEADER = 'X-Signalbird-Sdk';\n\n/** `node/2.6.0` - platform adları CONTRACT §14.1'deki listededir. */\nexport function sdkHeaderValue(platform: string): string {\n return `${platform}/${SDK_VERSION}`;\n}\n\n/** Başlık okuyabilen her şey: fetch `Headers`, ya da sahte bir yanıt. */\ninterface HeaderSource {\n get(name: string): string | null;\n}\n\nlet warned = false;\n\n/**\n * Yanıttaki sürüm durumuna bakar; eskiyse bir kez `console.warn` yazar.\n * Hiçbir koşulda hata fırlatmaz: sürüm uyarısı yüzünden müşterinin isteği\n * bozulmamalı.\n */\nexport function noteSdkStatus(headers: HeaderSource | null | undefined): void {\n if (warned || !headers) return;\n\n try {\n const status = headers.get('Signalbird-Sdk-Status');\n\n if (status !== 'outdated' && status !== 'unsupported') return;\n\n warned = true;\n\n const latest = headers.get('Signalbird-Sdk-Latest') ?? '?';\n const message = status === 'unsupported'\n ? `[signalbird] Bu SDK sürümü (${SDK_VERSION}) artık desteklenmiyor. Son sürüm: ${latest}. Paketi güncelleyin.`\n : `[signalbird] Yeni SDK sürümü var: ${latest} (kurulu: ${SDK_VERSION}).`;\n\n if (typeof console !== 'undefined') console.warn(message);\n } catch {\n // uyarı yazılamadıysa sessiz kal\n }\n}\n\n/** Yalnız testler için: uyarıyı yeniden kurar. */\nexport function resetSdkStatusWarning(): void {\n warned = false;\n}\n","/**\n * Telsiz gövdesini sunucunun kabul edeceği biçime getiren yardımcılar.\n *\n * Node ve tarayıcı istemcisi ortak kullanır. Sınıf metodu DEĞİL, modül\n * fonksiyonudur: `check-parity.mjs` istemci sınıfının girintili metotlarını\n * sayar ve buraya eklenen bir yardımcı Telsiz paritesini bozardı.\n */\n\n/**\n * API `message` alanını `max:4000` ile doğrular (Laravel → `mb_strlen`, yani\n * KOD NOKTASI). Sınırı aşan tek satır 422 alır ve toplu gönderimde bütün\n * paketi düşürür - 99 sağlam log bir uzun yığın izi yüzünden kaybolurdu.\n */\nexport const MAX_MESSAGE_LENGTH = 4000;\n\n/**\n * Mesajı 4000 kod noktasına kırpar.\n *\n * `.slice(0, 4000)` UTF-16 birimi sayar ve bir emoji'nin (vekil çift) ortasından\n * kesebilir; tek kalan vekil `\\ud83d` olarak gider ve PHP `json_decode` bütün\n * gövdeyi reddeder - düzeltmeye çalıştığımız hatanın aynısı. `Array.from` kod\n * noktası üzerinden yürür; pahalıdır, bu yüzden yalnız sınır aşıldığında çalışır.\n */\nexport function truncateMessage(message: string): string {\n const text = typeof message === 'string' ? message : String(message);\n\n if (text.length <= MAX_MESSAGE_LENGTH) {\n return text;\n }\n\n return Array.from(text).slice(0, MAX_MESSAGE_LENGTH).join('');\n}\n\n/**\n * `context`'i JSON'a güvenle çevrilebilir bir kopyaya dönüştürür.\n *\n * `JSON.stringify` döngüsel nesnede (ör. `req`, Mongoose belgesi) ve\n * `BigInt`'te İSTİSNA fırlatır. Node'da bu istisna isteğin içinde\n * yakalanıp `NETWORK_ERROR` diye raporlanıyordu - asıl sebep görünmüyordu.\n * Tarayıcıda daha kötüsü: başarısız toplu gönderim kuyruğa geri konur, aynı\n * satır her 3 saniyede tekrar patlar ve arkasındaki bütün loglar takılı kalırdı.\n *\n * - döngüsel başvuru → `\"[Circular]\"` (yalnız ATA zinciri sayılır: aynı nesneye\n * iki kardeş alandan başvurmak döngü değildir ve korunur)\n * - `Error` → `{name, message, stack}` (JSON'da `{}` olurdu, yani bilgi kaybı)\n * - `BigInt` → string\n * - `toJSON` taşıyan nesne (Date vb.) → onun çıktısı\n * - erişimde fırlatan getter → `\"[Unserializable]\"`\n */\nexport function toJsonSafe(value: unknown): unknown {\n const ancestors: object[] = [];\n\n const walk = (current: unknown): unknown => {\n if (typeof current === 'bigint') {\n return current.toString();\n }\n\n // Fonksiyon, symbol ve undefined olduğu gibi kalır: JSON.stringify onları\n // zaten atar (dizide null yapar); burada ayrıca karar vermeye gerek yok.\n if (current === null || typeof current !== 'object') {\n return current;\n }\n\n if (ancestors.includes(current)) {\n return '[Circular]';\n }\n\n if (current instanceof Error) {\n return { name: current.name, message: current.message, stack: current.stack };\n }\n\n const withToJson = current as { toJSON?: () => unknown };\n\n if (typeof withToJson.toJSON === 'function') {\n try {\n ancestors.push(current);\n return walk(withToJson.toJSON());\n } catch {\n return '[Unserializable]';\n } finally {\n ancestors.pop();\n }\n }\n\n ancestors.push(current);\n\n try {\n if (Array.isArray(current)) {\n return current.map((item) => walk(item));\n }\n\n const out: Record<string, unknown> = {};\n\n for (const key of Object.keys(current)) {\n let item: unknown;\n\n try {\n item = (current as Record<string, unknown>)[key];\n } catch {\n item = '[Unserializable]';\n }\n\n out[key] = walk(item);\n }\n\n return out;\n } finally {\n ancestors.pop();\n }\n };\n\n return walk(value);\n}\n\n/** `context` verilmediyse `undefined` kalır (gövdeye hiç girmez). */\nexport function safeContext(context?: Record<string, unknown>): Record<string, unknown> | undefined {\n if (context === undefined || context === null) {\n return undefined;\n }\n\n return toJsonSafe(context) as Record<string, unknown>;\n}\n","/**\n * signalbird/browser - tarayıcı istemcisi.\n *\n * Ayrı bir giriş noktası olmasının sebebi teknik değil, GÜVENLİKTİR: sunucu\n * anahtarı istemciye gömülemez ve sunucu `Origin` başlığı taşıyan bir istekte\n * onu zaten reddeder. Tarayıcı, açık anahtarı (`sb_public_live_…`) kullanır ve\n * güvenliği gizlilikten değil kısıttan gelir: yalnız izinli alan adlarından\n * çalışır ve Origin taşımayan istekte reddedilir (`ORIGIN_REQUIRED`).\n *\n * React, Vue, Angular ve düz JS aynı istemciyi kullanır; çatıya özel sarmalayıcı\n * yoktur çünkü gereken tek şey bir fonksiyon çağrısıdır.\n */\nimport { SDK_HEADER, noteSdkStatus, sdkHeaderValue } from '../shared/version';\nimport { safeContext, truncateMessage } from '../shared/serialize';\n\nexport type Level = 'debug' | 'info' | 'warn' | 'error' | 'critical';\n\nexport interface BrowserConfig {\n /** Açık anahtar (`sb_public_live_…`). Gizli anahtar BURAYA YAZILMAZ. */\n publicKey: string;\n baseUrl?: string;\n source?: string;\n /**\n * Kayıtlar tek tek değil, toplu gider. Kullanıcının tarayıcısından saniyede\n * onlarca istek çıkarmak hem yavaş hem pahalıdır.\n */\n flushIntervalMs?: number;\n maxQueue?: number;\n debug?: boolean;\n}\n\ninterface QueuedEvent {\n key: string;\n message: string;\n level?: Level;\n context?: Record<string, unknown>;\n source?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://live.signalbird.io/api';\n\nexport class SignalbirdBrowser {\n private queue: QueuedEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly baseUrl: string;\n private readonly maxQueue: number;\n\n constructor(private readonly config: BrowserConfig) {\n if (!config.publicKey?.startsWith('sb_public_live_')) {\n throw new Error(\n 'Signalbird: tarayıcı istemcisi açık anahtar ister (sb_public_live_…). ' +\n 'Gizli anahtarı (sb_secret_live_…) istemci koduna KOYMAYIN.'\n );\n }\n\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.maxQueue = config.maxQueue ?? 50;\n\n if (typeof window !== 'undefined') {\n this.timer = setInterval(() => void this.flush(), config.flushIntervalMs ?? 3000);\n\n // Sekme kapanırken kuyruk boşaltılır. `sendBeacon` sayfa ölürken bile\n // gider; normal fetch yarıda kesilirdi.\n window.addEventListener('pagehide', () => this.flushBeacon());\n }\n }\n\n /**\n * Kanalı bağlar ve yazacı döner - sunucu istemcisindeki `radio()` ile aynı\n * deyim (CONTRACT §1.1):\n *\n * sb.radio('sepet').error('sepet güncellenemedi', { cartId })\n *\n * `critical` BİLEREK yoktur: istemci kodu herkesin elindedir ve oradan\n * kritik alarm (sessiz saatleri delen bildirim) tetiklemek, kötü niyetli\n * birine ekibin telefonunu çaldırma imkânı verirdi. Gerekirse\n * `log(key, msg, 'critical')` hâlâ yazılabilir; kanal ayarı panelde durur.\n */\n radio(key: string) {\n return {\n debug: (message: string, context?: Record<string, unknown>) => this.log(key, message, 'debug', context),\n info: (message: string, context?: Record<string, unknown>) => this.log(key, message, 'info', context),\n warn: (message: string, context?: Record<string, unknown>) => this.log(key, message, 'warn', context),\n error: (message: string, context?: Record<string, unknown>) => this.log(key, message, 'error', context),\n };\n }\n\n log(key: string, message: string, level?: Level, context?: Record<string, unknown>): void {\n /*\n * Kırpma ve güvenli kopya KUYRUĞA GİRERKEN yapılır, gönderirken değil:\n * - 4000'i aşan tek mesaj bütün toplu paketi 422 ile düşürürdü;\n * - döngüsel `context` `JSON.stringify`'da patlar, `flush()` paketi geri\n * kuyruğa koyar ve aynı satır her turda tekrar patlayıp arkasındaki\n * bütün logları sonsuza dek bekletirdi;\n * - kopya o anki durumu saklar; nesne gönderime kadar değişse bile log,\n * yazıldığı andaki değeri taşır.\n */\n this.queue.push({\n key,\n message: truncateMessage(message),\n level,\n context: safeContext(context),\n source: this.config.source,\n });\n\n // Kuyruk dolduysa beklemeden gönder: bellekte sonsuza kadar biriktirmek,\n // logu hiç göndermemekten kötüdür.\n if (this.queue.length >= this.maxQueue) {\n void this.flush();\n }\n }\n\n info(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'info', context);\n }\n\n warn(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'warn', context);\n }\n\n error(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'error', context);\n }\n\n /**\n * Tarayıcıdaki yakalanmamış hataları bağlar.\n *\n * Varsayılan anahtar `browser`dır ve KRİTİK DEĞİLDİR: istemci tarafı kod\n * herkesin elindedir, oradan kritik alarm tetiklemek kötü niyetli birine\n * ekibin telefonunu çaldırma imkânı verirdi. Hangi kanalın kime bildirim\n * göndereceği panelde durur; oradan sessiz bırakılabilir.\n */\n captureErrors(key = 'browser'): () => void {\n const onError = (event: ErrorEvent) => {\n this.error(key, event.message, {\n file: event.filename,\n line: event.lineno,\n column: event.colno,\n url: window.location.href,\n });\n };\n\n const onRejection = (event: PromiseRejectionEvent) => {\n this.error(key, String(event.reason), { url: window.location.href });\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onRejection);\n\n return () => {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onRejection);\n };\n }\n\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const batch = this.queue.splice(0, 100);\n\n try {\n const response = await fetch(`${this.baseUrl}/v1/radio/log/batch`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Signalbird-Key': this.config.publicKey,\n [SDK_HEADER]: sdkHeaderValue('browser'),\n },\n body: JSON.stringify({ events: batch }),\n keepalive: true,\n });\n noteSdkStatus(response.headers);\n } catch (error) {\n if (this.config.debug) {\n console.warn('[signalbird] gönderilemedi', error);\n }\n // Kayıtlar geri konur ama kuyruk sınırı aşılmaz: ağ uzun süre kapalıysa\n // sekme belleği şişmemeli.\n this.queue = [...batch, ...this.queue].slice(0, this.maxQueue);\n }\n }\n\n /** Sayfa kapanırken son gönderim. */\n private flushBeacon(): void {\n if (this.queue.length === 0 || typeof navigator === 'undefined') return;\n\n /*\n * `text/plain`, `application/json` DEĞİL: `sendBeacon` CORS ön kontrolü\n * (preflight) yapamaz; \"basit\" olmayan içerik türü taşıyan cross-origin\n * beacon'ı tarayıcı hiç göndermez ve sayfa kapanırken son loglar sessizce\n * kaybolurdu. Gövde yine JSON'dur; API Telsiz log uçlarında text/plain\n * gövdeyi JSON olarak ayrıştırır. `fetch` yolu `application/json` kalır.\n */\n const blob = new Blob(\n [JSON.stringify({ events: this.queue.splice(0, 100) })],\n { type: 'text/plain;charset=UTF-8' }\n );\n\n // sendBeacon özel başlık taşıyamaz; anahtar ve SDK sürümü sorgu dizesinden gider.\n navigator.sendBeacon?.(\n `${this.baseUrl}/v1/radio/log/batch?k=${encodeURIComponent(this.config.publicKey)}` +\n `&sdk=${encodeURIComponent(sdkHeaderValue('browser'))}`,\n blob\n );\n }\n\n destroy(): void {\n if (this.timer) clearInterval(this.timer);\n void this.flush();\n }\n}\n\nlet singleton: SignalbirdBrowser | null = null;\n\n/** Uygulama başlangıcında bir kez çağrılır. */\nexport function initSignalbird(config: BrowserConfig): SignalbirdBrowser {\n singleton = new SignalbirdBrowser(config);\n return singleton;\n}\n\n/** Kurulmamışsa sessizce yok sayar - log çağrısı uygulamayı çökertmemeli. */\nexport function signalbird(): SignalbirdBrowser | null {\n return singleton;\n}\n"]}
package/dist/browser.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/shared/version.ts
2
- var SDK_VERSION = "2.6.0" ;
2
+ var SDK_VERSION = "2.9.0" ;
3
3
  var SDK_HEADER = "X-Signalbird-Sdk";
4
4
  function sdkHeaderValue(platform) {
5
5
  return `${platform}/${SDK_VERSION}`;
@@ -18,6 +18,70 @@ function noteSdkStatus(headers) {
18
18
  }
19
19
  }
20
20
 
21
+ // src/shared/serialize.ts
22
+ var MAX_MESSAGE_LENGTH = 4e3;
23
+ function truncateMessage(message) {
24
+ const text = typeof message === "string" ? message : String(message);
25
+ if (text.length <= MAX_MESSAGE_LENGTH) {
26
+ return text;
27
+ }
28
+ return Array.from(text).slice(0, MAX_MESSAGE_LENGTH).join("");
29
+ }
30
+ function toJsonSafe(value) {
31
+ const ancestors = [];
32
+ const walk = (current) => {
33
+ if (typeof current === "bigint") {
34
+ return current.toString();
35
+ }
36
+ if (current === null || typeof current !== "object") {
37
+ return current;
38
+ }
39
+ if (ancestors.includes(current)) {
40
+ return "[Circular]";
41
+ }
42
+ if (current instanceof Error) {
43
+ return { name: current.name, message: current.message, stack: current.stack };
44
+ }
45
+ const withToJson = current;
46
+ if (typeof withToJson.toJSON === "function") {
47
+ try {
48
+ ancestors.push(current);
49
+ return walk(withToJson.toJSON());
50
+ } catch {
51
+ return "[Unserializable]";
52
+ } finally {
53
+ ancestors.pop();
54
+ }
55
+ }
56
+ ancestors.push(current);
57
+ try {
58
+ if (Array.isArray(current)) {
59
+ return current.map((item) => walk(item));
60
+ }
61
+ const out = {};
62
+ for (const key of Object.keys(current)) {
63
+ let item;
64
+ try {
65
+ item = current[key];
66
+ } catch {
67
+ item = "[Unserializable]";
68
+ }
69
+ out[key] = walk(item);
70
+ }
71
+ return out;
72
+ } finally {
73
+ ancestors.pop();
74
+ }
75
+ };
76
+ return walk(value);
77
+ }
78
+ function safeContext(context) {
79
+ if (context === void 0 || context === null) {
80
+ return void 0;
81
+ }
82
+ return toJsonSafe(context);
83
+ }
84
+
21
85
  // src/browser/index.ts
22
86
  var DEFAULT_BASE_URL = "https://live.signalbird.io/api";
23
87
  var SignalbirdBrowser = class {
@@ -37,8 +101,33 @@ var SignalbirdBrowser = class {
37
101
  window.addEventListener("pagehide", () => this.flushBeacon());
38
102
  }
39
103
  }
104
+ /**
105
+ * Kanalı bağlar ve yazacı döner - sunucu istemcisindeki `radio()` ile aynı
106
+ * deyim (CONTRACT §1.1):
107
+ *
108
+ * sb.radio('sepet').error('sepet güncellenemedi', { cartId })
109
+ *
110
+ * `critical` BİLEREK yoktur: istemci kodu herkesin elindedir ve oradan
111
+ * kritik alarm (sessiz saatleri delen bildirim) tetiklemek, kötü niyetli
112
+ * birine ekibin telefonunu çaldırma imkânı verirdi. Gerekirse
113
+ * `log(key, msg, 'critical')` hâlâ yazılabilir; kanal ayarı panelde durur.
114
+ */
115
+ radio(key) {
116
+ return {
117
+ debug: (message, context) => this.log(key, message, "debug", context),
118
+ info: (message, context) => this.log(key, message, "info", context),
119
+ warn: (message, context) => this.log(key, message, "warn", context),
120
+ error: (message, context) => this.log(key, message, "error", context)
121
+ };
122
+ }
40
123
  log(key, message, level, context) {
41
- this.queue.push({ key, message, level, context, source: this.config.source });
124
+ this.queue.push({
125
+ key,
126
+ message: truncateMessage(message),
127
+ level,
128
+ context: safeContext(context),
129
+ source: this.config.source
130
+ });
42
131
  if (this.queue.length >= this.maxQueue) {
43
132
  void this.flush();
44
133
  }
@@ -106,7 +195,7 @@ var SignalbirdBrowser = class {
106
195
  if (this.queue.length === 0 || typeof navigator === "undefined") return;
107
196
  const blob = new Blob(
108
197
  [JSON.stringify({ events: this.queue.splice(0, 100) })],
109
- { type: "application/json" }
198
+ { type: "text/plain;charset=UTF-8" }
110
199
  );
111
200
  navigator.sendBeacon?.(
112
201
  `${this.baseUrl}/v1/radio/log/batch?k=${encodeURIComponent(this.config.publicKey)}&sdk=${encodeURIComponent(sdkHeaderValue("browser"))}`,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/version.ts","../src/browser/index.ts"],"names":[],"mappings":"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","file":"browser.mjs","sourcesContent":["/**\n * SDK sürüm bildirimi - CONTRACT §14.\n *\n * Her istek `X-Signalbird-Sdk: <platform>/<sürüm>` taşır; API bunu kaydeder\n * ve yanıtta `Signalbird-Sdk-Status` (current | outdated | unsupported) ile\n * `Signalbird-Sdk-Latest` döner. SDK eski olduğunu öğrenince geliştiriciye\n * süreç başına BİR KEZ uyarı yazar. Uyarı hata değildir: istek sonucu\n * değişmez, istisna fırlatılmaz.\n *\n * Sürüm numarası derlemede `VERSION` dosyasından gömülür (tsup `define`).\n */\n\ndeclare const __SB_VERSION__: string;\n\nexport const SDK_VERSION: string = typeof __SB_VERSION__ === 'string' ? __SB_VERSION__ : '0.0.0';\n\nexport const SDK_HEADER = 'X-Signalbird-Sdk';\n\n/** `node/2.6.0` - platform adları CONTRACT §14.1'deki listededir. */\nexport function sdkHeaderValue(platform: string): string {\n return `${platform}/${SDK_VERSION}`;\n}\n\n/** Başlık okuyabilen her şey: fetch `Headers`, ya da sahte bir yanıt. */\ninterface HeaderSource {\n get(name: string): string | null;\n}\n\nlet warned = false;\n\n/**\n * Yanıttaki sürüm durumuna bakar; eskiyse bir kez `console.warn` yazar.\n * Hiçbir koşulda hata fırlatmaz: sürüm uyarısı yüzünden müşterinin isteği\n * bozulmamalı.\n */\nexport function noteSdkStatus(headers: HeaderSource | null | undefined): void {\n if (warned || !headers) return;\n\n try {\n const status = headers.get('Signalbird-Sdk-Status');\n\n if (status !== 'outdated' && status !== 'unsupported') return;\n\n warned = true;\n\n const latest = headers.get('Signalbird-Sdk-Latest') ?? '?';\n const message = status === 'unsupported'\n ? `[signalbird] Bu SDK sürümü (${SDK_VERSION}) artık desteklenmiyor. Son sürüm: ${latest}. Paketi güncelleyin.`\n : `[signalbird] Yeni SDK sürümü var: ${latest} (kurulu: ${SDK_VERSION}).`;\n\n if (typeof console !== 'undefined') console.warn(message);\n } catch {\n // uyarı yazılamadıysa sessiz kal\n }\n}\n\n/** Yalnız testler için: uyarıyı yeniden kurar. */\nexport function resetSdkStatusWarning(): void {\n warned = false;\n}\n","/**\n * signalbird/browser - tarayıcı istemcisi.\n *\n * Ayrı bir giriş noktası olmasının sebebi teknik değil, GÜVENLİKTİR: sunucu\n * anahtarı istemciye gömülemez ve sunucu `Origin` başlığı taşıyan bir istekte\n * onu zaten reddeder. Tarayıcı, açık anahtarı (`sb_public_live_…`) kullanır ve\n * güvenliği gizlilikten değil kısıttan gelir: yalnız izinli alan adlarından\n * çalışır ve Origin taşımayan istekte reddedilir (`ORIGIN_REQUIRED`).\n *\n * React, Vue, Angular ve düz JS aynı istemciyi kullanır; çatıya özel sarmalayıcı\n * yoktur çünkü gereken tek şey bir fonksiyon çağrısıdır.\n */\nimport { SDK_HEADER, noteSdkStatus, sdkHeaderValue } from '../shared/version';\n\nexport type Level = 'debug' | 'info' | 'warn' | 'error' | 'critical';\n\nexport interface BrowserConfig {\n /** Açık anahtar (`sb_public_live_…`). Gizli anahtar BURAYA YAZILMAZ. */\n publicKey: string;\n baseUrl?: string;\n source?: string;\n /**\n * Kayıtlar tek tek değil, toplu gider. Kullanıcının tarayıcısından saniyede\n * onlarca istek çıkarmak hem yavaş hem pahalıdır.\n */\n flushIntervalMs?: number;\n maxQueue?: number;\n debug?: boolean;\n}\n\ninterface QueuedEvent {\n key: string;\n message: string;\n level?: Level;\n context?: Record<string, unknown>;\n source?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://live.signalbird.io/api';\n\nexport class SignalbirdBrowser {\n private queue: QueuedEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly baseUrl: string;\n private readonly maxQueue: number;\n\n constructor(private readonly config: BrowserConfig) {\n if (!config.publicKey?.startsWith('sb_public_live_')) {\n throw new Error(\n 'Signalbird: tarayıcı istemcisi açık anahtar ister (sb_public_live_…). ' +\n 'Gizli anahtarı (sb_secret_live_…) istemci koduna KOYMAYIN.'\n );\n }\n\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.maxQueue = config.maxQueue ?? 50;\n\n if (typeof window !== 'undefined') {\n this.timer = setInterval(() => void this.flush(), config.flushIntervalMs ?? 3000);\n\n // Sekme kapanırken kuyruk boşaltılır. `sendBeacon` sayfa ölürken bile\n // gider; normal fetch yarıda kesilirdi.\n window.addEventListener('pagehide', () => this.flushBeacon());\n }\n }\n\n log(key: string, message: string, level?: Level, context?: Record<string, unknown>): void {\n this.queue.push({ key, message, level, context, source: this.config.source });\n\n // Kuyruk dolduysa beklemeden gönder: bellekte sonsuza kadar biriktirmek,\n // logu hiç göndermemekten kötüdür.\n if (this.queue.length >= this.maxQueue) {\n void this.flush();\n }\n }\n\n info(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'info', context);\n }\n\n warn(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'warn', context);\n }\n\n error(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'error', context);\n }\n\n /**\n * Tarayıcıdaki yakalanmamış hataları bağlar.\n *\n * Varsayılan anahtar `browser`dır ve KRİTİK DEĞİLDİR: istemci tarafı kod\n * herkesin elindedir, oradan kritik alarm tetiklemek kötü niyetli birine\n * ekibin telefonunu çaldırma imkânı verirdi. Hangi kanalın kime bildirim\n * göndereceği panelde durur; oradan sessiz bırakılabilir.\n */\n captureErrors(key = 'browser'): () => void {\n const onError = (event: ErrorEvent) => {\n this.error(key, event.message, {\n file: event.filename,\n line: event.lineno,\n column: event.colno,\n url: window.location.href,\n });\n };\n\n const onRejection = (event: PromiseRejectionEvent) => {\n this.error(key, String(event.reason), { url: window.location.href });\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onRejection);\n\n return () => {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onRejection);\n };\n }\n\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const batch = this.queue.splice(0, 100);\n\n try {\n const response = await fetch(`${this.baseUrl}/v1/radio/log/batch`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Signalbird-Key': this.config.publicKey,\n [SDK_HEADER]: sdkHeaderValue('browser'),\n },\n body: JSON.stringify({ events: batch }),\n keepalive: true,\n });\n noteSdkStatus(response.headers);\n } catch (error) {\n if (this.config.debug) {\n console.warn('[signalbird] gönderilemedi', error);\n }\n // Kayıtlar geri konur ama kuyruk sınırı aşılmaz: ağ uzun süre kapalıysa\n // sekme belleği şişmemeli.\n this.queue = [...batch, ...this.queue].slice(0, this.maxQueue);\n }\n }\n\n /** Sayfa kapanırken son gönderim. */\n private flushBeacon(): void {\n if (this.queue.length === 0 || typeof navigator === 'undefined') return;\n\n const blob = new Blob(\n [JSON.stringify({ events: this.queue.splice(0, 100) })],\n { type: 'application/json' }\n );\n\n // sendBeacon özel başlık taşıyamaz; anahtar ve SDK sürümü sorgu dizesinden gider.\n navigator.sendBeacon?.(\n `${this.baseUrl}/v1/radio/log/batch?k=${encodeURIComponent(this.config.publicKey)}` +\n `&sdk=${encodeURIComponent(sdkHeaderValue('browser'))}`,\n blob\n );\n }\n\n destroy(): void {\n if (this.timer) clearInterval(this.timer);\n void this.flush();\n }\n}\n\nlet singleton: SignalbirdBrowser | null = null;\n\n/** Uygulama başlangıcında bir kez çağrılır. */\nexport function initSignalbird(config: BrowserConfig): SignalbirdBrowser {\n singleton = new SignalbirdBrowser(config);\n return singleton;\n}\n\n/** Kurulmamışsa sessizce yok sayar - log çağrısı uygulamayı çökertmemeli. */\nexport function signalbird(): SignalbirdBrowser | null {\n return singleton;\n}\n"]}
1
+ {"version":3,"sources":["../src/shared/version.ts","../src/shared/serialize.ts","../src/browser/index.ts"],"names":[],"mappings":"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","file":"browser.mjs","sourcesContent":["/**\n * SDK sürüm bildirimi - CONTRACT §14.\n *\n * Her istek `X-Signalbird-Sdk: <platform>/<sürüm>` taşır; API bunu kaydeder\n * ve yanıtta `Signalbird-Sdk-Status` (current | outdated | unsupported) ile\n * `Signalbird-Sdk-Latest` döner. SDK eski olduğunu öğrenince geliştiriciye\n * süreç başına BİR KEZ uyarı yazar. Uyarı hata değildir: istek sonucu\n * değişmez, istisna fırlatılmaz.\n *\n * Sürüm numarası derlemede `VERSION` dosyasından gömülür (tsup `define`).\n */\n\ndeclare const __SB_VERSION__: string;\n\nexport const SDK_VERSION: string = typeof __SB_VERSION__ === 'string' ? __SB_VERSION__ : '0.0.0';\n\nexport const SDK_HEADER = 'X-Signalbird-Sdk';\n\n/** `node/2.6.0` - platform adları CONTRACT §14.1'deki listededir. */\nexport function sdkHeaderValue(platform: string): string {\n return `${platform}/${SDK_VERSION}`;\n}\n\n/** Başlık okuyabilen her şey: fetch `Headers`, ya da sahte bir yanıt. */\ninterface HeaderSource {\n get(name: string): string | null;\n}\n\nlet warned = false;\n\n/**\n * Yanıttaki sürüm durumuna bakar; eskiyse bir kez `console.warn` yazar.\n * Hiçbir koşulda hata fırlatmaz: sürüm uyarısı yüzünden müşterinin isteği\n * bozulmamalı.\n */\nexport function noteSdkStatus(headers: HeaderSource | null | undefined): void {\n if (warned || !headers) return;\n\n try {\n const status = headers.get('Signalbird-Sdk-Status');\n\n if (status !== 'outdated' && status !== 'unsupported') return;\n\n warned = true;\n\n const latest = headers.get('Signalbird-Sdk-Latest') ?? '?';\n const message = status === 'unsupported'\n ? `[signalbird] Bu SDK sürümü (${SDK_VERSION}) artık desteklenmiyor. Son sürüm: ${latest}. Paketi güncelleyin.`\n : `[signalbird] Yeni SDK sürümü var: ${latest} (kurulu: ${SDK_VERSION}).`;\n\n if (typeof console !== 'undefined') console.warn(message);\n } catch {\n // uyarı yazılamadıysa sessiz kal\n }\n}\n\n/** Yalnız testler için: uyarıyı yeniden kurar. */\nexport function resetSdkStatusWarning(): void {\n warned = false;\n}\n","/**\n * Telsiz gövdesini sunucunun kabul edeceği biçime getiren yardımcılar.\n *\n * Node ve tarayıcı istemcisi ortak kullanır. Sınıf metodu DEĞİL, modül\n * fonksiyonudur: `check-parity.mjs` istemci sınıfının girintili metotlarını\n * sayar ve buraya eklenen bir yardımcı Telsiz paritesini bozardı.\n */\n\n/**\n * API `message` alanını `max:4000` ile doğrular (Laravel → `mb_strlen`, yani\n * KOD NOKTASI). Sınırı aşan tek satır 422 alır ve toplu gönderimde bütün\n * paketi düşürür - 99 sağlam log bir uzun yığın izi yüzünden kaybolurdu.\n */\nexport const MAX_MESSAGE_LENGTH = 4000;\n\n/**\n * Mesajı 4000 kod noktasına kırpar.\n *\n * `.slice(0, 4000)` UTF-16 birimi sayar ve bir emoji'nin (vekil çift) ortasından\n * kesebilir; tek kalan vekil `\\ud83d` olarak gider ve PHP `json_decode` bütün\n * gövdeyi reddeder - düzeltmeye çalıştığımız hatanın aynısı. `Array.from` kod\n * noktası üzerinden yürür; pahalıdır, bu yüzden yalnız sınır aşıldığında çalışır.\n */\nexport function truncateMessage(message: string): string {\n const text = typeof message === 'string' ? message : String(message);\n\n if (text.length <= MAX_MESSAGE_LENGTH) {\n return text;\n }\n\n return Array.from(text).slice(0, MAX_MESSAGE_LENGTH).join('');\n}\n\n/**\n * `context`'i JSON'a güvenle çevrilebilir bir kopyaya dönüştürür.\n *\n * `JSON.stringify` döngüsel nesnede (ör. `req`, Mongoose belgesi) ve\n * `BigInt`'te İSTİSNA fırlatır. Node'da bu istisna isteğin içinde\n * yakalanıp `NETWORK_ERROR` diye raporlanıyordu - asıl sebep görünmüyordu.\n * Tarayıcıda daha kötüsü: başarısız toplu gönderim kuyruğa geri konur, aynı\n * satır her 3 saniyede tekrar patlar ve arkasındaki bütün loglar takılı kalırdı.\n *\n * - döngüsel başvuru → `\"[Circular]\"` (yalnız ATA zinciri sayılır: aynı nesneye\n * iki kardeş alandan başvurmak döngü değildir ve korunur)\n * - `Error` → `{name, message, stack}` (JSON'da `{}` olurdu, yani bilgi kaybı)\n * - `BigInt` → string\n * - `toJSON` taşıyan nesne (Date vb.) → onun çıktısı\n * - erişimde fırlatan getter → `\"[Unserializable]\"`\n */\nexport function toJsonSafe(value: unknown): unknown {\n const ancestors: object[] = [];\n\n const walk = (current: unknown): unknown => {\n if (typeof current === 'bigint') {\n return current.toString();\n }\n\n // Fonksiyon, symbol ve undefined olduğu gibi kalır: JSON.stringify onları\n // zaten atar (dizide null yapar); burada ayrıca karar vermeye gerek yok.\n if (current === null || typeof current !== 'object') {\n return current;\n }\n\n if (ancestors.includes(current)) {\n return '[Circular]';\n }\n\n if (current instanceof Error) {\n return { name: current.name, message: current.message, stack: current.stack };\n }\n\n const withToJson = current as { toJSON?: () => unknown };\n\n if (typeof withToJson.toJSON === 'function') {\n try {\n ancestors.push(current);\n return walk(withToJson.toJSON());\n } catch {\n return '[Unserializable]';\n } finally {\n ancestors.pop();\n }\n }\n\n ancestors.push(current);\n\n try {\n if (Array.isArray(current)) {\n return current.map((item) => walk(item));\n }\n\n const out: Record<string, unknown> = {};\n\n for (const key of Object.keys(current)) {\n let item: unknown;\n\n try {\n item = (current as Record<string, unknown>)[key];\n } catch {\n item = '[Unserializable]';\n }\n\n out[key] = walk(item);\n }\n\n return out;\n } finally {\n ancestors.pop();\n }\n };\n\n return walk(value);\n}\n\n/** `context` verilmediyse `undefined` kalır (gövdeye hiç girmez). */\nexport function safeContext(context?: Record<string, unknown>): Record<string, unknown> | undefined {\n if (context === undefined || context === null) {\n return undefined;\n }\n\n return toJsonSafe(context) as Record<string, unknown>;\n}\n","/**\n * signalbird/browser - tarayıcı istemcisi.\n *\n * Ayrı bir giriş noktası olmasının sebebi teknik değil, GÜVENLİKTİR: sunucu\n * anahtarı istemciye gömülemez ve sunucu `Origin` başlığı taşıyan bir istekte\n * onu zaten reddeder. Tarayıcı, açık anahtarı (`sb_public_live_…`) kullanır ve\n * güvenliği gizlilikten değil kısıttan gelir: yalnız izinli alan adlarından\n * çalışır ve Origin taşımayan istekte reddedilir (`ORIGIN_REQUIRED`).\n *\n * React, Vue, Angular ve düz JS aynı istemciyi kullanır; çatıya özel sarmalayıcı\n * yoktur çünkü gereken tek şey bir fonksiyon çağrısıdır.\n */\nimport { SDK_HEADER, noteSdkStatus, sdkHeaderValue } from '../shared/version';\nimport { safeContext, truncateMessage } from '../shared/serialize';\n\nexport type Level = 'debug' | 'info' | 'warn' | 'error' | 'critical';\n\nexport interface BrowserConfig {\n /** Açık anahtar (`sb_public_live_…`). Gizli anahtar BURAYA YAZILMAZ. */\n publicKey: string;\n baseUrl?: string;\n source?: string;\n /**\n * Kayıtlar tek tek değil, toplu gider. Kullanıcının tarayıcısından saniyede\n * onlarca istek çıkarmak hem yavaş hem pahalıdır.\n */\n flushIntervalMs?: number;\n maxQueue?: number;\n debug?: boolean;\n}\n\ninterface QueuedEvent {\n key: string;\n message: string;\n level?: Level;\n context?: Record<string, unknown>;\n source?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://live.signalbird.io/api';\n\nexport class SignalbirdBrowser {\n private queue: QueuedEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly baseUrl: string;\n private readonly maxQueue: number;\n\n constructor(private readonly config: BrowserConfig) {\n if (!config.publicKey?.startsWith('sb_public_live_')) {\n throw new Error(\n 'Signalbird: tarayıcı istemcisi açık anahtar ister (sb_public_live_…). ' +\n 'Gizli anahtarı (sb_secret_live_…) istemci koduna KOYMAYIN.'\n );\n }\n\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.maxQueue = config.maxQueue ?? 50;\n\n if (typeof window !== 'undefined') {\n this.timer = setInterval(() => void this.flush(), config.flushIntervalMs ?? 3000);\n\n // Sekme kapanırken kuyruk boşaltılır. `sendBeacon` sayfa ölürken bile\n // gider; normal fetch yarıda kesilirdi.\n window.addEventListener('pagehide', () => this.flushBeacon());\n }\n }\n\n /**\n * Kanalı bağlar ve yazacı döner - sunucu istemcisindeki `radio()` ile aynı\n * deyim (CONTRACT §1.1):\n *\n * sb.radio('sepet').error('sepet güncellenemedi', { cartId })\n *\n * `critical` BİLEREK yoktur: istemci kodu herkesin elindedir ve oradan\n * kritik alarm (sessiz saatleri delen bildirim) tetiklemek, kötü niyetli\n * birine ekibin telefonunu çaldırma imkânı verirdi. Gerekirse\n * `log(key, msg, 'critical')` hâlâ yazılabilir; kanal ayarı panelde durur.\n */\n radio(key: string) {\n return {\n debug: (message: string, context?: Record<string, unknown>) => this.log(key, message, 'debug', context),\n info: (message: string, context?: Record<string, unknown>) => this.log(key, message, 'info', context),\n warn: (message: string, context?: Record<string, unknown>) => this.log(key, message, 'warn', context),\n error: (message: string, context?: Record<string, unknown>) => this.log(key, message, 'error', context),\n };\n }\n\n log(key: string, message: string, level?: Level, context?: Record<string, unknown>): void {\n /*\n * Kırpma ve güvenli kopya KUYRUĞA GİRERKEN yapılır, gönderirken değil:\n * - 4000'i aşan tek mesaj bütün toplu paketi 422 ile düşürürdü;\n * - döngüsel `context` `JSON.stringify`'da patlar, `flush()` paketi geri\n * kuyruğa koyar ve aynı satır her turda tekrar patlayıp arkasındaki\n * bütün logları sonsuza dek bekletirdi;\n * - kopya o anki durumu saklar; nesne gönderime kadar değişse bile log,\n * yazıldığı andaki değeri taşır.\n */\n this.queue.push({\n key,\n message: truncateMessage(message),\n level,\n context: safeContext(context),\n source: this.config.source,\n });\n\n // Kuyruk dolduysa beklemeden gönder: bellekte sonsuza kadar biriktirmek,\n // logu hiç göndermemekten kötüdür.\n if (this.queue.length >= this.maxQueue) {\n void this.flush();\n }\n }\n\n info(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'info', context);\n }\n\n warn(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'warn', context);\n }\n\n error(key: string, message: string, context?: Record<string, unknown>) {\n this.log(key, message, 'error', context);\n }\n\n /**\n * Tarayıcıdaki yakalanmamış hataları bağlar.\n *\n * Varsayılan anahtar `browser`dır ve KRİTİK DEĞİLDİR: istemci tarafı kod\n * herkesin elindedir, oradan kritik alarm tetiklemek kötü niyetli birine\n * ekibin telefonunu çaldırma imkânı verirdi. Hangi kanalın kime bildirim\n * göndereceği panelde durur; oradan sessiz bırakılabilir.\n */\n captureErrors(key = 'browser'): () => void {\n const onError = (event: ErrorEvent) => {\n this.error(key, event.message, {\n file: event.filename,\n line: event.lineno,\n column: event.colno,\n url: window.location.href,\n });\n };\n\n const onRejection = (event: PromiseRejectionEvent) => {\n this.error(key, String(event.reason), { url: window.location.href });\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onRejection);\n\n return () => {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onRejection);\n };\n }\n\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const batch = this.queue.splice(0, 100);\n\n try {\n const response = await fetch(`${this.baseUrl}/v1/radio/log/batch`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Signalbird-Key': this.config.publicKey,\n [SDK_HEADER]: sdkHeaderValue('browser'),\n },\n body: JSON.stringify({ events: batch }),\n keepalive: true,\n });\n noteSdkStatus(response.headers);\n } catch (error) {\n if (this.config.debug) {\n console.warn('[signalbird] gönderilemedi', error);\n }\n // Kayıtlar geri konur ama kuyruk sınırı aşılmaz: ağ uzun süre kapalıysa\n // sekme belleği şişmemeli.\n this.queue = [...batch, ...this.queue].slice(0, this.maxQueue);\n }\n }\n\n /** Sayfa kapanırken son gönderim. */\n private flushBeacon(): void {\n if (this.queue.length === 0 || typeof navigator === 'undefined') return;\n\n /*\n * `text/plain`, `application/json` DEĞİL: `sendBeacon` CORS ön kontrolü\n * (preflight) yapamaz; \"basit\" olmayan içerik türü taşıyan cross-origin\n * beacon'ı tarayıcı hiç göndermez ve sayfa kapanırken son loglar sessizce\n * kaybolurdu. Gövde yine JSON'dur; API Telsiz log uçlarında text/plain\n * gövdeyi JSON olarak ayrıştırır. `fetch` yolu `application/json` kalır.\n */\n const blob = new Blob(\n [JSON.stringify({ events: this.queue.splice(0, 100) })],\n { type: 'text/plain;charset=UTF-8' }\n );\n\n // sendBeacon özel başlık taşıyamaz; anahtar ve SDK sürümü sorgu dizesinden gider.\n navigator.sendBeacon?.(\n `${this.baseUrl}/v1/radio/log/batch?k=${encodeURIComponent(this.config.publicKey)}` +\n `&sdk=${encodeURIComponent(sdkHeaderValue('browser'))}`,\n blob\n );\n }\n\n destroy(): void {\n if (this.timer) clearInterval(this.timer);\n void this.flush();\n }\n}\n\nlet singleton: SignalbirdBrowser | null = null;\n\n/** Uygulama başlangıcında bir kez çağrılır. */\nexport function initSignalbird(config: BrowserConfig): SignalbirdBrowser {\n singleton = new SignalbirdBrowser(config);\n return singleton;\n}\n\n/** Kurulmamışsa sessizce yok sayar - log çağrısı uygulamayı çökertmemeli. */\nexport function signalbird(): SignalbirdBrowser | null {\n return singleton;\n}\n"]}
package/dist/index.d.mts CHANGED
@@ -57,7 +57,7 @@ interface LogResult {
57
57
  ok: boolean;
58
58
  /** Sunucunun döndüğü olay kimliği (rev_…). */
59
59
  eventId?: string;
60
- /** Reddedildiyse sebep: INVALID_KEY, MODULE_DISABLED, LIMIT_REACHED… */
60
+ /** Reddedildiyse sebep: DOMAIN_KEY_INVALID, MODULE_DISABLED, MODULE_KEY_DISABLED, LIMIT_REACHED… */
61
61
  code?: string;
62
62
  status?: number;
63
63
  }
@@ -114,13 +114,22 @@ declare class SignalbirdClient {
114
114
  error: (message: string, context?: Record<string, unknown>) => Promise<LogResult>;
115
115
  critical: (message: string, context?: Record<string, unknown>) => Promise<LogResult>;
116
116
  };
117
- /** Tek kayıt gönderir. */
117
+ /**
118
+ * Tek kayıt gönderir.
119
+ *
120
+ * `message` 4000 kod noktasına kırpılır (API sınırı; aşan satır 422 alırdı)
121
+ * ve `context` güvenli kopyaya çevrilir: döngüsel nesne ya da BigInt artık
122
+ * `NETWORK_ERROR` gibi görünen bir istisnaya dönüşmez.
123
+ */
118
124
  log(input: LogInput): Promise<LogResult>;
119
125
  /**
120
126
  * Toplu gönderim - 100 kayda kadar.
121
127
  *
122
128
  * Kısmi başarı normaldir (kota tam ortada dolabilir), o yüzden sonuç tek bir
123
129
  * durum değil satır satır döner.
130
+ *
131
+ * Doğrulama ise satır satır DEĞİLDİR: tek bir geçersiz satır (4000'i aşan
132
+ * mesaj) bütün paketi 422 ile düşürür. Bu yüzden kırpma burada da yapılır.
124
133
  */
125
134
  batch(events: LogInput[]): Promise<BatchResult>;
126
135
  debugLog(key: string, message: string, context?: Record<string, unknown>): Promise<LogResult>;
@@ -128,6 +137,17 @@ declare class SignalbirdClient {
128
137
  warn(key: string, message: string, context?: Record<string, unknown>): Promise<LogResult>;
129
138
  error(key: string, message: string, context?: Record<string, unknown>): Promise<LogResult>;
130
139
  critical(key: string, message: string, context?: Record<string, unknown>): Promise<LogResult>;
140
+ /**
141
+ * Kimlik doğrulama hash'i (CONTRACT §15.2) - sohbet/push ziyaretçisinin
142
+ * `external_id`'sini GÜVENİLİR kılar.
143
+ *
144
+ * identity_hash = hex(HMAC-SHA256(hex(SHA-256(secretKey)), externalId))
145
+ *
146
+ * Anahtar gizli anahtarın kendisi değil SHA-256 özetidir: sunucu anahtarı
147
+ * düz saklamaz. Hash sunucuda üretilir, sayfaya `external_id` ile birlikte
148
+ * yazılır; gizli anahtar istemciye İNMEZ.
149
+ */
150
+ identityHash(externalId: string): string;
131
151
  /**
132
152
  * Yakalanmamış hataları Telsiz'e bağlar.
133
153
  *
@@ -148,7 +168,7 @@ declare class SignalbirdClient {
148
168
  * bulunur ve iki doküman arasında çeviri tablosu gerekmez.
149
169
  */
150
170
  interface MessagingConfig {
151
- /** Takım API anahtarı (`sb_…`). GİZLİDİR, yalnız sunucuda kullanılır. */
171
+ /** Gizli domain anahtarı (`sb_secret_live_…`). Yalnız sunucuda kullanılır. */
152
172
  domainKey: string;
153
173
  /** Varsayılan: https://live.signalbird.io/api */
154
174
  baseUrl?: string;
@@ -174,22 +194,96 @@ type SbResult$1<T> = {
174
194
  /** İleti sınıfı - API'de zorunludur ve varsayılanı YOKTUR (hukuki kapı). */
175
195
  type MessageClass = 'transactional' | 'commercial';
176
196
  type Channel = 'email' | 'sms' | 'push';
197
+ /** E-posta eki - içerik base64; toplam çözülmüş boyut sınırı sunucudadır (7 MB). */
198
+ interface EmailAttachment {
199
+ filename: string;
200
+ mime?: string;
201
+ /** Dosya içeriği, base64. */
202
+ content_b64: string;
203
+ }
204
+ /**
205
+ * `POST /v1/email/send` gövdesi - alanlar API doğrulamasıyla birebir
206
+ * (signalbird.api `Api\V1\MessagingController::sendEmail`).
207
+ *
208
+ * İçerik iki yoldan gelir: ya `subject` + `body`, ya panelde tanımlı bir
209
+ * şablon (`template` adıyla ya da `template_id` ile). Şablon verilmediyse
210
+ * `subject` ve `body` ZORUNLUDUR (API: `required_without_all:template_id,template`);
211
+ * verildiyse ikisi de şablondan gelir ve istenirse ezilebilir.
212
+ *
213
+ * Tip bilerek arayüz olarak kaldı (birleşim tipi değil): kullanıcı kodunda
214
+ * `extends SendEmailInput` yazan herkes kırılırdı.
215
+ */
177
216
  interface SendEmailInput {
217
+ /** Alıcı e-posta adresi. */
178
218
  to: string;
219
+ /** Zorunlu, varsayılanı yok: işlemsel ile ticari arasındaki fark hukukidir. */
179
220
  class: MessageClass;
180
- subject: string;
221
+ /** Konu (en fazla 255). Şablon yoksa zorunlu. */
222
+ subject?: string;
223
+ /** Gövde - HTML ya da düz metin. Şablon yoksa zorunlu. */
181
224
  body?: string;
182
- template_hash?: string;
225
+ /** Panelde tanımlı şablonun ADI (en fazla 190). Ad tercih edilir: şablon yeniden yaratılsa da kod değişmez. */
226
+ template?: string;
227
+ /** Panelde tanımlı şablonun kimliği. */
228
+ template_id?: number;
229
+ /** Şablon/gövde değişkenleri - `{{ad}}` yerine geçer. */
183
230
  vars?: Record<string, unknown>;
231
+ /**
232
+ * GÖNDERİCİ KANALI: panelde adresle birlikte açılan `email` modül anahtarı
233
+ * (`noReply`). From adresini kanal seçer - PHP'deki
234
+ * `Signalbird::sendMail('noReply')` karşılığı. Kanala adres bağlanmamışsa
235
+ * 422 `SENDER_NOT_CONFIGURED`; tanımsız kanal `MODULE_KEY_NOT_FOUND`.
236
+ */
237
+ module_key?: string;
238
+ /** Belirli bir doğrulanmış gönderen alan adından çıksın. */
184
239
  sending_domain_id?: number;
240
+ /** Gönderen ADRES seçimi (destek@…); alan adını da belirler. `module_key` verilirse kanalınki geçerlidir. */
241
+ sending_address_id?: number;
242
+ /** Signalbird'deki kişi kaydı - açılma/tıklama geçmişi ona yazılsın. */
185
243
  contact_id?: number;
244
+ /** Görünen gönderen adı (en fazla 120). Zarf adresi değil. */
245
+ from_name?: string;
246
+ /** "Yanıtla" adresi. */
247
+ reply_to?: string;
248
+ /** En fazla 5 ek. */
249
+ attachments?: EmailAttachment[];
250
+ /**
251
+ * @deprecated API bu alanı hiç okumaz ve SDK onu GÖNDERMEZ (2.9.0). Şablon
252
+ * için `template` (ad) ya da `template_id` kullanın. Yalnız eski kodun tip
253
+ * denetiminde kırılmaması için tanımlı; başka bir alana eşlenmez.
254
+ */
255
+ template_hash?: string;
186
256
  }
257
+ /**
258
+ * `POST /v1/sms/send` gövdesi - alanlar API doğrulamasıyla birebir
259
+ * (signalbird.api `Api\V1\MessagingController::sendSms`).
260
+ *
261
+ * İçerik ya `body` ya da panelde tanımlı bir şablondur (`template` adıyla ya
262
+ * da `template_id` ile). Şablon verilmediyse `body` ZORUNLUDUR (API:
263
+ * `required_without_all:template_id,template`).
264
+ *
265
+ * E-postanın aksine SMS ucunda gönderici KANALI (`module_key`) yoktur;
266
+ * gönderen adı `sender` ile seçilir.
267
+ */
187
268
  interface SendSmsInput {
269
+ /** Alıcı telefon (en fazla 20). Sunucu normalize eder; geçersizse 422 `INVALID_PHONE`. */
188
270
  to: string;
271
+ /** Zorunlu, varsayılanı yok: işlemsel ile ticari arasındaki fark hukukidir. */
189
272
  class: MessageClass;
190
- body: string;
273
+ /** Mesaj metni (en fazla 1600). Şablon yoksa zorunlu. */
274
+ body?: string;
275
+ /** Panelde tanımlı şablonun ADI (en fazla 190). */
276
+ template?: string;
277
+ /** Panelde tanımlı şablonun kimliği. */
278
+ template_id?: number;
279
+ /** Şablon/gövde değişkenleri - `{{ad}}` yerine geçer. */
280
+ vars?: Record<string, unknown>;
281
+ /** Marka (SMS başlığı/kotası bu markadan). */
191
282
  brand_id?: number;
283
+ /** Signalbird'deki kişi kaydı. */
192
284
  contact_id?: number;
285
+ /** Onaylı SMS gönderici adı (en fazla 11). Verilmezse şirketin varsayılanı. */
286
+ sender?: string;
193
287
  }
194
288
  interface SendPushInput {
195
289
  /** Cihaz token'ı, `contact:<id>` ya da `external:<external_id>`. */
@@ -599,7 +693,7 @@ interface EmbedToken {
599
693
  }
600
694
 
601
695
  interface ManagementConfig {
602
- /** Takım API anahtarı (`sb_…`) - `radio:*`, `chat:*`, `apps:*` scope'larıyla. */
696
+ /** Gizli domain anahtarı (`sb_secret_live_…`). Scope yoktur (v2); yalnız gömme jetonu ayrı onay ister. */
603
697
  domainKey: string;
604
698
  /** Varsayılan: https://live.signalbird.io/api */
605
699
  baseUrl?: string;
@@ -913,9 +1007,9 @@ interface TeamEmbedTokenInput {
913
1007
  * kayıtlarına dokunur; başka takımın kaydı 404 döner.
914
1008
  *
915
1009
  * Neden ayrı sınıf: Gönderim (`SignalbirdMessaging`) ileti gönderir ve kota
916
- * harcar; bu istemci yapılandırma değiştirir. Aynı anahtar ailesini kullanırlar
917
- * (`sb_…`) ama scope'ları ve hata kümeleri farklıdır - tek sınıfta birleşseydi
918
- * "hangi scope gerekiyordu" sorusu her metotta yeniden sorulurdu.
1010
+ * harcar; bu istemci yapılandırma değiştirir. Aynı gizli domain anahtarını
1011
+ * (`sb_secret_live_…`) kullanırlar ama hata kümeleri farklıdır - tek sınıfta
1012
+ * birleşseydi her metotta "bu kod hangi yüzeyin" sorusu sorulurdu.
919
1013
  *
920
1014
  * Sözleşme: docs/CONTRACT.md § 10
921
1015
  */
@@ -1055,7 +1149,7 @@ declare class SignalbirdManagement {
1055
1149
  *
1056
1150
  * **Bu, CLAUDE.md'deki "Admin yüzeyi OLMAYACAK" kuralının bilinçli
1057
1151
  * istisnasıdır** ve istisna olduğu için ayrı anahtar türü taşır. Kural,
1058
- * müşterinin kendi anahtarıyla (`sb_`) şirket açamaması içindi; o kural aynen
1152
+ * müşterinin kendi anahtarıyla şirket açamaması içindi; o kural aynen
1059
1153
  * duruyor. Sözleşmeli partner farklı bir taraftır.
1060
1154
  *
1061
1155
  * Gizli anahtar **asla tarayıcıya inmez**: gömme jetonunu partner'ın
@@ -1162,11 +1256,12 @@ declare function verifyWebhook(rawBody: string | Uint8Array, signatureHeader: st
1162
1256
  * Node betikleri buradan alır. TARAYICI için `signalbird/browser`
1163
1257
  * kullanılır - gizli anahtar istemciye inmez.
1164
1258
  *
1165
- * Üç sunucu istemcisi vardır; anahtarları ve kapıları farklıdır:
1166
- * - `SignalbirdClient` → Telsiz (log yazma), `sb_secret_live_…`
1167
- * - `SignalbirdMessaging` → Gönderim (e-posta/SMS/push/kişi/kampanya), `sb_…`
1168
- * - `SignalbirdManagement` → Yönetim (Telsiz projesi, sohbet gelen kutusu,
1169
- * uygulama kaydı), `sb_…` + `radio|chat|apps` scope'ları
1259
+ * Sunucu istemcilerinin HEPSİ aynı gizli domain anahtarını (`sb_secret_live_…`)
1260
+ * kullanır; ayrım anahtarda değil, kapıdadır:
1261
+ * - `SignalbirdClient` → Telsiz (log yazma)
1262
+ * - `SignalbirdMessaging` → Gönderim (e-posta/SMS/push/kişi/kampanya)
1263
+ * - `SignalbirdManagement` → Yönetim (olay akışı, modül anahtarları, sohbet
1264
+ * gelen kutusu)
1170
1265
  * - `SignalbirdPartner` → Partner (müşteri sağlama, modül yetkisi, gömme),
1171
1266
  * gizli anahtar - yalnız sözleşmeli platformlar
1172
1267
  *
@@ -1190,8 +1285,8 @@ declare function resetSignalbird(): void;
1190
1285
  /**
1191
1286
  * Ortam değişkeninden kurulan paylaşımlı yönetim istemcisi.
1192
1287
  *
1193
- * `SIGNALBIRD_DOMAIN_KEY` okunur (yoksa `SIGNALBIRD_DOMAIN_KEY` - ikisi de aynı
1194
- * takım anahtarı ailesidir ve çoğu kurulumda tek anahtar kullanılır).
1288
+ * `SIGNALBIRD_DOMAIN_KEY` okunur - Telsiz ve Gönderim ile aynı gizli domain
1289
+ * anahtarı (`sb_secret_live_…`).
1195
1290
  *
1196
1291
  * import { management } from 'signalbird'
1197
1292
  * await management().createModuleKey('logger', { title: 'Kritik API hatası' })
@@ -1200,4 +1295,4 @@ declare function management(config?: Partial<ManagementConfig>): SignalbirdManag
1200
1295
  /** Test ve sıcak yeniden yükleme için yönetim istemcisini sıfırlar. */
1201
1296
  declare function resetManagement(): void;
1202
1297
 
1203
- export { type AddDomainInput, type AddDomainResult, type AppDevice, type AppPlatform, type Batch, type BatchResult, type BulkContactsInput, type BulkContactsResult, type CampaignCreateResult, type CampaignDetail, type CannedReply, type CannedReplyInput, type Channel, type ChatConversation, type ChatMessage, type ChatVisitor, type Contact, type ContactInput, type ContactList, type ConversationStatus, type CreateCampaignInput, type CreateCompanyInput, type CreateCompanyResult, type CreateContactListInput, DEFAULT_BASE_URL, type DnsRecord, type EmbedModule, type EmbedToken, type EmbedTokenInput, type GrantModuleInput, type Level, type ListAppDevicesQuery, type ListCampaignMessagesQuery, type ListCampaignsQuery, type ListChatMessagesQuery, type ListContactsQuery, type ListConversationsQuery, type ListMessagesQuery, type ListRadioEventsQuery, type LogInput, type LogResult, type ManagementConfig, type Message, type MessageClass, type MessagingConfig, type MessagingErrorCode, type ModuleEntitlement, type Paginated$1 as Paginated, type PartnerCompany, type PartnerConfig, type PartnerDomain, type PartnerOwnerInput, type PartnerUser, type PartnerUserInput, type RadioEvent, type RadioLevel, type ReplyInput, type SbResult$1 as SbResult, type SendEmailInput, type SendPushInput, type SendResult, type SendSmsInput, SignalbirdClient, type SignalbirdConfig, SignalbirdError, SignalbirdManagement, SignalbirdMessaging, SignalbirdPartner, type SmsPreview, type StartConversationInput, type TeamEmbedTokenInput, type UpdateConversationInput, type UpdateVisitorInput, type UptimeIncident, type UptimeRange, type UptimeReport, type VerifyDomainResult, management, resetManagement, resetSignalbird, signalbird, verifyWebhook };
1298
+ export { type AddDomainInput, type AddDomainResult, type AppDevice, type AppPlatform, type Batch, type BatchResult, type BulkContactsInput, type BulkContactsResult, type CampaignCreateResult, type CampaignDetail, type CannedReply, type CannedReplyInput, type Channel, type ChatConversation, type ChatMessage, type ChatVisitor, type Contact, type ContactInput, type ContactList, type ConversationStatus, type CreateCampaignInput, type CreateCompanyInput, type CreateCompanyResult, type CreateContactListInput, DEFAULT_BASE_URL, type DnsRecord, type EmailAttachment, type EmbedModule, type EmbedToken, type EmbedTokenInput, type GrantModuleInput, type Level, type ListAppDevicesQuery, type ListCampaignMessagesQuery, type ListCampaignsQuery, type ListChatMessagesQuery, type ListContactsQuery, type ListConversationsQuery, type ListMessagesQuery, type ListRadioEventsQuery, type LogInput, type LogResult, type ManagementConfig, type Message, type MessageClass, type MessagingConfig, type MessagingErrorCode, type ModuleEntitlement, type Paginated$1 as Paginated, type PartnerCompany, type PartnerConfig, type PartnerDomain, type PartnerOwnerInput, type PartnerUser, type PartnerUserInput, type RadioEvent, type RadioLevel, type ReplyInput, type SbResult$1 as SbResult, type SendEmailInput, type SendPushInput, type SendResult, type SendSmsInput, SignalbirdClient, type SignalbirdConfig, SignalbirdError, SignalbirdManagement, SignalbirdMessaging, SignalbirdPartner, type SmsPreview, type StartConversationInput, type TeamEmbedTokenInput, type UpdateConversationInput, type UpdateVisitorInput, type UptimeIncident, type UptimeRange, type UptimeReport, type VerifyDomainResult, management, resetManagement, resetSignalbird, signalbird, verifyWebhook };