signalbird 2.5.0 → 2.6.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 +37 -33
- package/dist/angular.d.mts +4 -4
- package/dist/angular.d.ts +4 -4
- package/dist/angular.js +56 -13
- package/dist/angular.js.map +1 -1
- package/dist/angular.mjs +56 -13
- package/dist/angular.mjs.map +1 -1
- package/dist/app.d.mts +37 -47
- package/dist/app.d.ts +37 -47
- package/dist/app.js +55 -12
- package/dist/app.js.map +1 -1
- package/dist/app.mjs +55 -12
- package/dist/app.mjs.map +1 -1
- package/dist/browser.d.mts +1 -13
- package/dist/browser.d.ts +1 -13
- package/dist/browser.js +25 -3
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +25 -3
- package/dist/browser.mjs.map +1 -1
- package/dist/embed.d.mts +6 -6
- package/dist/embed.d.ts +6 -6
- package/dist/embed.js +1 -1
- package/dist/embed.js.map +1 -1
- package/dist/embed.mjs +1 -1
- package/dist/embed.mjs.map +1 -1
- package/dist/index.d.mts +50 -50
- package/dist/index.d.ts +50 -50
- package/dist/index.js +48 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +48 -22
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +2 -2
- package/dist/react-native.d.ts +2 -2
- package/dist/react-native.js +55 -12
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +55 -12
- package/dist/react-native.mjs.map +1 -1
- package/dist/react.d.mts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +55 -12
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +55 -12
- package/dist/react.mjs.map +1 -1
- package/dist/signalbird.js +20 -20
- package/dist/vue.d.mts +3 -3
- package/dist/vue.d.ts +3 -3
- package/dist/vue.js +55 -12
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +55 -12
- package/dist/vue.mjs.map +1 -1
- package/package.json +2 -2
package/dist/browser.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/browser/index.ts"],"names":[],"mappings":"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","file":"browser.mjs","sourcesContent":["/**\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 */\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 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 },\n body: JSON.stringify({ events: batch }),\n keepalive: true,\n });\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 sorgu dizesinden gider.\n navigator.sendBeacon?.(\n `${this.baseUrl}/v1/radio/log/batch?k=${encodeURIComponent(this.config.publicKey)}`,\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/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"]}
|
package/dist/embed.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Gömme (embed) yüzeyi
|
|
2
|
+
* Gömme (embed) yüzeyi - Signalbird panel ekranını BAŞKA bir panelin içinde
|
|
3
3
|
* çalıştırır.
|
|
4
4
|
*
|
|
5
5
|
* Sözleşme: signalbird.api/docs/PARTNER_PLATFORM_2026-08-20.md §2.6, §4.4.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* içine çalışan ekranı kurar. Ev sahibi ne iframe yazar, ne yükseklik hesaplar,
|
|
11
11
|
* ne jeton ömrü yönetir.
|
|
12
12
|
*/
|
|
13
|
-
/** Gömülebilir modüller
|
|
13
|
+
/** Gömülebilir modüller - Signalbird `Partner::EMBED_MODULES` ile birebir. */
|
|
14
14
|
type EmbedModule = 'chat' | 'monitoring' | 'campaigns' | 'contacts' | 'radio' | 'messages';
|
|
15
15
|
type EmbedTheme = 'light' | 'dark' | 'auto';
|
|
16
16
|
/**
|
|
@@ -18,7 +18,7 @@ type EmbedTheme = 'light' | 'dark' | 'auto';
|
|
|
18
18
|
* tarayıcıya asla inmez. SDK yalnızca sonucu ister.
|
|
19
19
|
*
|
|
20
20
|
* Dönüş: Signalbird'ün `POST /v1/partner/companies/{ext}/embed` yanıtındaki
|
|
21
|
-
* `url`
|
|
21
|
+
* `url` - ya doğrudan string, ya `{url}` taşıyan nesne (ev sahibinin API
|
|
22
22
|
* zarfını soymasına gerek kalmasın diye ikisi de kabul edilir).
|
|
23
23
|
*/
|
|
24
24
|
type EmbedMinter = (context: {
|
|
@@ -43,7 +43,7 @@ interface EmbedOptions {
|
|
|
43
43
|
/** Varsayılan `auto`: ev sahibi sayfanın karanlık kipini izler. */
|
|
44
44
|
theme?: EmbedTheme;
|
|
45
45
|
locale?: string;
|
|
46
|
-
/** Vurgu rengi (hex, `#` olmadan da olur)
|
|
46
|
+
/** Vurgu rengi (hex, `#` olmadan da olur) - Signalbird ekranı buna uyar. */
|
|
47
47
|
accent?: string;
|
|
48
48
|
/**
|
|
49
49
|
* `auto` (varsayılan): yükseklik gömülü ekranın bildirdiği kadar olur.
|
|
@@ -51,7 +51,7 @@ interface EmbedOptions {
|
|
|
51
51
|
* sabit yükseklik genelde daha iyidir.
|
|
52
52
|
*/
|
|
53
53
|
height?: number | 'auto';
|
|
54
|
-
/** `auto` yükseklikte alt sınır
|
|
54
|
+
/** `auto` yükseklikte alt sınır - ekran yüklenirken çerçeve zıplamasın. */
|
|
55
55
|
minHeight?: number;
|
|
56
56
|
/** iframe'e eklenecek CSS sınıfı (ev sahibinin kendi kenarlığı, gölgesi…). */
|
|
57
57
|
className?: string;
|
|
@@ -73,7 +73,7 @@ interface EmbedHandle {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* Gömme çekirdeği
|
|
76
|
+
* Gömme çekirdeği - çatısız, bağımlılıksız.
|
|
77
77
|
*
|
|
78
78
|
* Ev sahibi tarafında TEK satır:
|
|
79
79
|
*
|
package/dist/embed.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Gömme (embed) yüzeyi
|
|
2
|
+
* Gömme (embed) yüzeyi - Signalbird panel ekranını BAŞKA bir panelin içinde
|
|
3
3
|
* çalıştırır.
|
|
4
4
|
*
|
|
5
5
|
* Sözleşme: signalbird.api/docs/PARTNER_PLATFORM_2026-08-20.md §2.6, §4.4.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* içine çalışan ekranı kurar. Ev sahibi ne iframe yazar, ne yükseklik hesaplar,
|
|
11
11
|
* ne jeton ömrü yönetir.
|
|
12
12
|
*/
|
|
13
|
-
/** Gömülebilir modüller
|
|
13
|
+
/** Gömülebilir modüller - Signalbird `Partner::EMBED_MODULES` ile birebir. */
|
|
14
14
|
type EmbedModule = 'chat' | 'monitoring' | 'campaigns' | 'contacts' | 'radio' | 'messages';
|
|
15
15
|
type EmbedTheme = 'light' | 'dark' | 'auto';
|
|
16
16
|
/**
|
|
@@ -18,7 +18,7 @@ type EmbedTheme = 'light' | 'dark' | 'auto';
|
|
|
18
18
|
* tarayıcıya asla inmez. SDK yalnızca sonucu ister.
|
|
19
19
|
*
|
|
20
20
|
* Dönüş: Signalbird'ün `POST /v1/partner/companies/{ext}/embed` yanıtındaki
|
|
21
|
-
* `url`
|
|
21
|
+
* `url` - ya doğrudan string, ya `{url}` taşıyan nesne (ev sahibinin API
|
|
22
22
|
* zarfını soymasına gerek kalmasın diye ikisi de kabul edilir).
|
|
23
23
|
*/
|
|
24
24
|
type EmbedMinter = (context: {
|
|
@@ -43,7 +43,7 @@ interface EmbedOptions {
|
|
|
43
43
|
/** Varsayılan `auto`: ev sahibi sayfanın karanlık kipini izler. */
|
|
44
44
|
theme?: EmbedTheme;
|
|
45
45
|
locale?: string;
|
|
46
|
-
/** Vurgu rengi (hex, `#` olmadan da olur)
|
|
46
|
+
/** Vurgu rengi (hex, `#` olmadan da olur) - Signalbird ekranı buna uyar. */
|
|
47
47
|
accent?: string;
|
|
48
48
|
/**
|
|
49
49
|
* `auto` (varsayılan): yükseklik gömülü ekranın bildirdiği kadar olur.
|
|
@@ -51,7 +51,7 @@ interface EmbedOptions {
|
|
|
51
51
|
* sabit yükseklik genelde daha iyidir.
|
|
52
52
|
*/
|
|
53
53
|
height?: number | 'auto';
|
|
54
|
-
/** `auto` yükseklikte alt sınır
|
|
54
|
+
/** `auto` yükseklikte alt sınır - ekran yüklenirken çerçeve zıplamasın. */
|
|
55
55
|
minHeight?: number;
|
|
56
56
|
/** iframe'e eklenecek CSS sınıfı (ev sahibinin kendi kenarlığı, gölgesi…). */
|
|
57
57
|
className?: string;
|
|
@@ -73,7 +73,7 @@ interface EmbedHandle {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* Gömme çekirdeği
|
|
76
|
+
* Gömme çekirdeği - çatısız, bağımlılıksız.
|
|
77
77
|
*
|
|
78
78
|
* Ev sahibi tarafında TEK satır:
|
|
79
79
|
*
|
package/dist/embed.js
CHANGED
|
@@ -152,7 +152,7 @@ function createEmbed(options) {
|
|
|
152
152
|
async mount(targetSelector) {
|
|
153
153
|
const element = typeof targetSelector === "string" ? document.querySelector(targetSelector) : targetSelector;
|
|
154
154
|
if (!(element instanceof HTMLElement)) {
|
|
155
|
-
throw new Error("Signalbird: g\xF6mme kab\u0131 bulunamad\u0131
|
|
155
|
+
throw new Error("Signalbird: g\xF6mme kab\u0131 bulunamad\u0131 - " + String(targetSelector));
|
|
156
156
|
}
|
|
157
157
|
container = element;
|
|
158
158
|
destroyed = false;
|
package/dist/embed.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/embed/element.ts"],"names":[],"mappings":"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","file":"embed.js","sourcesContent":["/**\n * Gömme çekirdeği — çatısız, bağımlılıksız.\n *\n * Ev sahibi tarafında TEK satır:\n *\n * Signalbird.embed({ module: 'chat', mint }).mount('#sb-chat')\n *\n * Ne yapar:\n * • jetonu ev sahibinin sunucusundan ister (partner anahtarı tarayıcıya inmez)\n * • iframe'i kurar, tema/dil/vurgu rengini adrese işler\n * • gömülü ekranın `postMessage` ile bildirdiği yüksekliği uygular\n * • jeton süresi dolmuş/geçersizse anlaşılır bir hata ve \"yeniden dene\" çizer\n * • `destroy()` ile dinleyicileri bırakır (SPA'da sızıntı yok)\n *\n * NE YAPMAZ: modülün satın alınıp alınmadığına bakmaz. O kapı ev sahibinin\n * kendi satış kaydındadır ve `mint` çağrısı 403 dönerek söyler; SDK yalnız\n * mesajı gösterir.\n */\nimport type { EmbedEvent, EmbedHandle, EmbedOptions, EmbedTheme } from './types';\n\ntype Listener = (payload?: unknown) => void;\n\nconst TEXT = {\n tr: {\n loading: 'Yükleniyor…',\n failed: 'Ekran yüklenemedi.',\n expired: 'Bu bağlantının süresi doldu.',\n retry: 'Yeniden dene',\n },\n en: {\n loading: 'Loading…',\n failed: 'The screen could not be loaded.',\n expired: 'This link has expired.',\n retry: 'Try again',\n },\n} as const;\n\n/** Ev sahibi sayfanın kipi: açık talep > `data-theme`/`.dark` > işletim sistemi. */\nfunction resolveTheme(theme: EmbedTheme | undefined): 'light' | 'dark' {\n if (theme === 'light' || theme === 'dark') return theme;\n\n if (typeof document !== 'undefined') {\n const root = document.documentElement;\n\n if (root.classList.contains('dark') || root.dataset.theme === 'dark') return 'dark';\n if (root.classList.contains('light') || root.dataset.theme === 'light') return 'light';\n }\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n\n return 'light';\n}\n\n/** `{url}`, `{data:{url}}` ya da düz string — üçü de kabul edilir. */\nfunction readUrl(result: unknown): string | null {\n if (typeof result === 'string') return result || null;\n\n if (result && typeof result === 'object') {\n const record = result as { url?: unknown; data?: { url?: unknown } };\n\n if (typeof record.url === 'string') return record.url;\n if (record.data && typeof record.data.url === 'string') return record.data.url;\n }\n\n return null;\n}\n\nexport function createEmbed(options: EmbedOptions): EmbedHandle {\n const text = TEXT[options.language ?? 'tr'];\n const listeners = new Map<EmbedEvent, Set<Listener>>();\n\n let container: HTMLElement | null = null;\n let frame: HTMLIFrameElement | null = null;\n let messageHandler: ((event: MessageEvent) => void) | null = null;\n let theme: EmbedTheme = options.theme ?? 'auto';\n let destroyed = false;\n\n const emit = (event: EmbedEvent, payload?: unknown) => {\n listeners.get(event)?.forEach((fn) => {\n try {\n fn(payload);\n } catch (error) {\n console.warn('[signalbird]', error);\n }\n });\n };\n\n const clear = () => {\n if (messageHandler) {\n window.removeEventListener('message', messageHandler);\n messageHandler = null;\n }\n\n frame = null;\n\n if (container) container.textContent = '';\n };\n\n const status = (message: string, withRetry: boolean) => {\n if (!container) return;\n\n container.textContent = '';\n\n const box = document.createElement('div');\n box.setAttribute('data-signalbird-status', '');\n box.style.cssText =\n 'display:flex;align-items:center;justify-content:center;gap:12px;' +\n `min-height:${options.minHeight ?? 220}px;font:13px/1.5 system-ui,-apple-system,sans-serif;` +\n 'color:#6b7280;text-align:center;padding:24px;';\n\n const label = document.createElement('span');\n label.textContent = message;\n box.appendChild(label);\n\n if (withRetry) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = text.retry;\n button.style.cssText =\n 'border:1px solid currentColor;border-radius:8px;background:transparent;' +\n 'color:inherit;padding:4px 10px;font:inherit;cursor:pointer;';\n button.addEventListener('click', () => void render());\n box.appendChild(button);\n }\n\n container.appendChild(box);\n };\n\n /** Jetonu alır ve iframe'i kurar. Her çağrı YENİ jeton demektir. */\n const render = async (): Promise<void> => {\n if (!container || destroyed) return;\n\n clear();\n status(text.loading, false);\n\n const applied = resolveTheme(theme);\n let url: string | null = null;\n\n try {\n if (options.url) {\n // Elde hazır jeton varsa İLK kurulum onu kullanır: ev sahibi jetonu\n // zaten almış olabilir (ör. betiğin hangi kökenden yükleneceğini o\n // yanıttan öğrenir). Jeton tek kullanımlıktır, bu yüzden tüketilir;\n // sonraki `refresh()` çağrıları `mint` ister.\n url = options.url;\n options = { ...options, url: undefined };\n } else if (options.mint) {\n url = readUrl(\n await options.mint({ module: options.module, theme: applied, locale: options.locale }),\n );\n }\n } catch (error) {\n emit('error', error);\n status(error instanceof Error ? error.message : text.failed, true);\n\n return;\n }\n\n if (!url) {\n emit('error', new Error('EMBED_URL_MISSING'));\n status(text.expired, Boolean(options.mint));\n\n return;\n }\n\n // Tema/dil/vurgu adrese işlenir: gömülü ekran ev sahibiyle aynı görünsün.\n let target = url;\n\n try {\n const parsed = new URL(url);\n\n parsed.searchParams.set('theme', applied);\n if (options.locale) parsed.searchParams.set('locale', options.locale);\n if (options.accent) parsed.searchParams.set('accent', options.accent.replace(/^#/, ''));\n target = parsed.toString();\n } catch {\n // Göreli adres: olduğu gibi kullanılır.\n }\n\n const iframe = document.createElement('iframe');\n\n iframe.src = target;\n iframe.title = 'Signalbird';\n iframe.style.cssText = 'width:100%;border:0;display:block;';\n iframe.style.height = `${typeof options.height === 'number' ? options.height : options.minHeight ?? 640}px`;\n iframe.setAttribute('allow', 'clipboard-write; fullscreen; autoplay');\n /*\n * `allow-same-origin` ŞART: gömülü ekran jetonu KENDİ kökeninde oturuma\n * çevirir; sandbox onu kısarsa ekran hiç açılmaz. `allow-top-navigation`\n * VERİLMEZ — gömülü ekran ev sahibi panelin tamamını başka bir adrese\n * götüremesin. Ses (yeni mesaj) ve dosya yükleme için `allow-popups` ve\n * `allow-downloads` gerekir.\n */\n iframe.setAttribute(\n 'sandbox',\n 'allow-same-origin allow-scripts allow-forms allow-popups allow-downloads',\n );\n iframe.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');\n iframe.setAttribute('loading', 'lazy');\n\n if (options.className) iframe.className = options.className;\n\n container.textContent = '';\n container.appendChild(iframe);\n frame = iframe;\n\n // Gömülü ekran yüksekliğini ve hazır olduğunu bildirir. Gönderen KONTROL\n // EDİLİR (`event.source`): sayfadaki başka bir iframe bizim çerçevemizi\n // büyütemesin.\n messageHandler = (event: MessageEvent) => {\n if (!frame || event.source !== frame.contentWindow) return;\n\n const data = event.data as { type?: string; px?: number; module?: string } | null;\n\n if (!data || typeof data.type !== 'string') return;\n\n if (data.type === 'signalbird:ready') {\n emit('ready', data.module);\n\n return;\n }\n\n if (data.type === 'signalbird:height' && typeof data.px === 'number') {\n emit('height', data.px);\n\n if ((options.height ?? 'auto') === 'auto') {\n const px = Math.max(data.px, options.minHeight ?? 220);\n\n frame.style.height = `${px}px`;\n }\n }\n };\n\n window.addEventListener('message', messageHandler);\n };\n\n return {\n async mount(targetSelector) {\n const element =\n typeof targetSelector === 'string' ? document.querySelector(targetSelector) : targetSelector;\n\n if (!(element instanceof HTMLElement)) {\n throw new Error('Signalbird: gömme kabı bulunamadı — ' + String(targetSelector));\n }\n\n container = element;\n destroyed = false;\n\n await render();\n },\n\n refresh: () => render(),\n\n async setTheme(next) {\n theme = next;\n await render();\n },\n\n destroy() {\n destroyed = true;\n clear();\n listeners.clear();\n container = null;\n },\n\n on(event, handler) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(handler);\n },\n\n off(event, handler) {\n listeners.get(event)?.delete(handler);\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/embed/element.ts"],"names":[],"mappings":"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","file":"embed.js","sourcesContent":["/**\n * Gömme çekirdeği - çatısız, bağımlılıksız.\n *\n * Ev sahibi tarafında TEK satır:\n *\n * Signalbird.embed({ module: 'chat', mint }).mount('#sb-chat')\n *\n * Ne yapar:\n * • jetonu ev sahibinin sunucusundan ister (partner anahtarı tarayıcıya inmez)\n * • iframe'i kurar, tema/dil/vurgu rengini adrese işler\n * • gömülü ekranın `postMessage` ile bildirdiği yüksekliği uygular\n * • jeton süresi dolmuş/geçersizse anlaşılır bir hata ve \"yeniden dene\" çizer\n * • `destroy()` ile dinleyicileri bırakır (SPA'da sızıntı yok)\n *\n * NE YAPMAZ: modülün satın alınıp alınmadığına bakmaz. O kapı ev sahibinin\n * kendi satış kaydındadır ve `mint` çağrısı 403 dönerek söyler; SDK yalnız\n * mesajı gösterir.\n */\nimport type { EmbedEvent, EmbedHandle, EmbedOptions, EmbedTheme } from './types';\n\ntype Listener = (payload?: unknown) => void;\n\nconst TEXT = {\n tr: {\n loading: 'Yükleniyor…',\n failed: 'Ekran yüklenemedi.',\n expired: 'Bu bağlantının süresi doldu.',\n retry: 'Yeniden dene',\n },\n en: {\n loading: 'Loading…',\n failed: 'The screen could not be loaded.',\n expired: 'This link has expired.',\n retry: 'Try again',\n },\n} as const;\n\n/** Ev sahibi sayfanın kipi: açık talep > `data-theme`/`.dark` > işletim sistemi. */\nfunction resolveTheme(theme: EmbedTheme | undefined): 'light' | 'dark' {\n if (theme === 'light' || theme === 'dark') return theme;\n\n if (typeof document !== 'undefined') {\n const root = document.documentElement;\n\n if (root.classList.contains('dark') || root.dataset.theme === 'dark') return 'dark';\n if (root.classList.contains('light') || root.dataset.theme === 'light') return 'light';\n }\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n\n return 'light';\n}\n\n/** `{url}`, `{data:{url}}` ya da düz string - üçü de kabul edilir. */\nfunction readUrl(result: unknown): string | null {\n if (typeof result === 'string') return result || null;\n\n if (result && typeof result === 'object') {\n const record = result as { url?: unknown; data?: { url?: unknown } };\n\n if (typeof record.url === 'string') return record.url;\n if (record.data && typeof record.data.url === 'string') return record.data.url;\n }\n\n return null;\n}\n\nexport function createEmbed(options: EmbedOptions): EmbedHandle {\n const text = TEXT[options.language ?? 'tr'];\n const listeners = new Map<EmbedEvent, Set<Listener>>();\n\n let container: HTMLElement | null = null;\n let frame: HTMLIFrameElement | null = null;\n let messageHandler: ((event: MessageEvent) => void) | null = null;\n let theme: EmbedTheme = options.theme ?? 'auto';\n let destroyed = false;\n\n const emit = (event: EmbedEvent, payload?: unknown) => {\n listeners.get(event)?.forEach((fn) => {\n try {\n fn(payload);\n } catch (error) {\n console.warn('[signalbird]', error);\n }\n });\n };\n\n const clear = () => {\n if (messageHandler) {\n window.removeEventListener('message', messageHandler);\n messageHandler = null;\n }\n\n frame = null;\n\n if (container) container.textContent = '';\n };\n\n const status = (message: string, withRetry: boolean) => {\n if (!container) return;\n\n container.textContent = '';\n\n const box = document.createElement('div');\n box.setAttribute('data-signalbird-status', '');\n box.style.cssText =\n 'display:flex;align-items:center;justify-content:center;gap:12px;' +\n `min-height:${options.minHeight ?? 220}px;font:13px/1.5 system-ui,-apple-system,sans-serif;` +\n 'color:#6b7280;text-align:center;padding:24px;';\n\n const label = document.createElement('span');\n label.textContent = message;\n box.appendChild(label);\n\n if (withRetry) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = text.retry;\n button.style.cssText =\n 'border:1px solid currentColor;border-radius:8px;background:transparent;' +\n 'color:inherit;padding:4px 10px;font:inherit;cursor:pointer;';\n button.addEventListener('click', () => void render());\n box.appendChild(button);\n }\n\n container.appendChild(box);\n };\n\n /** Jetonu alır ve iframe'i kurar. Her çağrı YENİ jeton demektir. */\n const render = async (): Promise<void> => {\n if (!container || destroyed) return;\n\n clear();\n status(text.loading, false);\n\n const applied = resolveTheme(theme);\n let url: string | null = null;\n\n try {\n if (options.url) {\n // Elde hazır jeton varsa İLK kurulum onu kullanır: ev sahibi jetonu\n // zaten almış olabilir (ör. betiğin hangi kökenden yükleneceğini o\n // yanıttan öğrenir). Jeton tek kullanımlıktır, bu yüzden tüketilir;\n // sonraki `refresh()` çağrıları `mint` ister.\n url = options.url;\n options = { ...options, url: undefined };\n } else if (options.mint) {\n url = readUrl(\n await options.mint({ module: options.module, theme: applied, locale: options.locale }),\n );\n }\n } catch (error) {\n emit('error', error);\n status(error instanceof Error ? error.message : text.failed, true);\n\n return;\n }\n\n if (!url) {\n emit('error', new Error('EMBED_URL_MISSING'));\n status(text.expired, Boolean(options.mint));\n\n return;\n }\n\n // Tema/dil/vurgu adrese işlenir: gömülü ekran ev sahibiyle aynı görünsün.\n let target = url;\n\n try {\n const parsed = new URL(url);\n\n parsed.searchParams.set('theme', applied);\n if (options.locale) parsed.searchParams.set('locale', options.locale);\n if (options.accent) parsed.searchParams.set('accent', options.accent.replace(/^#/, ''));\n target = parsed.toString();\n } catch {\n // Göreli adres: olduğu gibi kullanılır.\n }\n\n const iframe = document.createElement('iframe');\n\n iframe.src = target;\n iframe.title = 'Signalbird';\n iframe.style.cssText = 'width:100%;border:0;display:block;';\n iframe.style.height = `${typeof options.height === 'number' ? options.height : options.minHeight ?? 640}px`;\n iframe.setAttribute('allow', 'clipboard-write; fullscreen; autoplay');\n /*\n * `allow-same-origin` ŞART: gömülü ekran jetonu KENDİ kökeninde oturuma\n * çevirir; sandbox onu kısarsa ekran hiç açılmaz. `allow-top-navigation`\n * VERİLMEZ - gömülü ekran ev sahibi panelin tamamını başka bir adrese\n * götüremesin. Ses (yeni mesaj) ve dosya yükleme için `allow-popups` ve\n * `allow-downloads` gerekir.\n */\n iframe.setAttribute(\n 'sandbox',\n 'allow-same-origin allow-scripts allow-forms allow-popups allow-downloads',\n );\n iframe.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');\n iframe.setAttribute('loading', 'lazy');\n\n if (options.className) iframe.className = options.className;\n\n container.textContent = '';\n container.appendChild(iframe);\n frame = iframe;\n\n // Gömülü ekran yüksekliğini ve hazır olduğunu bildirir. Gönderen KONTROL\n // EDİLİR (`event.source`): sayfadaki başka bir iframe bizim çerçevemizi\n // büyütemesin.\n messageHandler = (event: MessageEvent) => {\n if (!frame || event.source !== frame.contentWindow) return;\n\n const data = event.data as { type?: string; px?: number; module?: string } | null;\n\n if (!data || typeof data.type !== 'string') return;\n\n if (data.type === 'signalbird:ready') {\n emit('ready', data.module);\n\n return;\n }\n\n if (data.type === 'signalbird:height' && typeof data.px === 'number') {\n emit('height', data.px);\n\n if ((options.height ?? 'auto') === 'auto') {\n const px = Math.max(data.px, options.minHeight ?? 220);\n\n frame.style.height = `${px}px`;\n }\n }\n };\n\n window.addEventListener('message', messageHandler);\n };\n\n return {\n async mount(targetSelector) {\n const element =\n typeof targetSelector === 'string' ? document.querySelector(targetSelector) : targetSelector;\n\n if (!(element instanceof HTMLElement)) {\n throw new Error('Signalbird: gömme kabı bulunamadı - ' + String(targetSelector));\n }\n\n container = element;\n destroyed = false;\n\n await render();\n },\n\n refresh: () => render(),\n\n async setTheme(next) {\n theme = next;\n await render();\n },\n\n destroy() {\n destroyed = true;\n clear();\n listeners.clear();\n container = null;\n },\n\n on(event, handler) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(handler);\n },\n\n off(event, handler) {\n listeners.get(event)?.delete(handler);\n },\n };\n}\n"]}
|
package/dist/embed.mjs
CHANGED
|
@@ -150,7 +150,7 @@ function createEmbed(options) {
|
|
|
150
150
|
async mount(targetSelector) {
|
|
151
151
|
const element = typeof targetSelector === "string" ? document.querySelector(targetSelector) : targetSelector;
|
|
152
152
|
if (!(element instanceof HTMLElement)) {
|
|
153
|
-
throw new Error("Signalbird: g\xF6mme kab\u0131 bulunamad\u0131
|
|
153
|
+
throw new Error("Signalbird: g\xF6mme kab\u0131 bulunamad\u0131 - " + String(targetSelector));
|
|
154
154
|
}
|
|
155
155
|
container = element;
|
|
156
156
|
destroyed = false;
|
package/dist/embed.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/embed/element.ts"],"names":[],"mappings":"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","file":"embed.mjs","sourcesContent":["/**\n * Gömme çekirdeği — çatısız, bağımlılıksız.\n *\n * Ev sahibi tarafında TEK satır:\n *\n * Signalbird.embed({ module: 'chat', mint }).mount('#sb-chat')\n *\n * Ne yapar:\n * • jetonu ev sahibinin sunucusundan ister (partner anahtarı tarayıcıya inmez)\n * • iframe'i kurar, tema/dil/vurgu rengini adrese işler\n * • gömülü ekranın `postMessage` ile bildirdiği yüksekliği uygular\n * • jeton süresi dolmuş/geçersizse anlaşılır bir hata ve \"yeniden dene\" çizer\n * • `destroy()` ile dinleyicileri bırakır (SPA'da sızıntı yok)\n *\n * NE YAPMAZ: modülün satın alınıp alınmadığına bakmaz. O kapı ev sahibinin\n * kendi satış kaydındadır ve `mint` çağrısı 403 dönerek söyler; SDK yalnız\n * mesajı gösterir.\n */\nimport type { EmbedEvent, EmbedHandle, EmbedOptions, EmbedTheme } from './types';\n\ntype Listener = (payload?: unknown) => void;\n\nconst TEXT = {\n tr: {\n loading: 'Yükleniyor…',\n failed: 'Ekran yüklenemedi.',\n expired: 'Bu bağlantının süresi doldu.',\n retry: 'Yeniden dene',\n },\n en: {\n loading: 'Loading…',\n failed: 'The screen could not be loaded.',\n expired: 'This link has expired.',\n retry: 'Try again',\n },\n} as const;\n\n/** Ev sahibi sayfanın kipi: açık talep > `data-theme`/`.dark` > işletim sistemi. */\nfunction resolveTheme(theme: EmbedTheme | undefined): 'light' | 'dark' {\n if (theme === 'light' || theme === 'dark') return theme;\n\n if (typeof document !== 'undefined') {\n const root = document.documentElement;\n\n if (root.classList.contains('dark') || root.dataset.theme === 'dark') return 'dark';\n if (root.classList.contains('light') || root.dataset.theme === 'light') return 'light';\n }\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n\n return 'light';\n}\n\n/** `{url}`, `{data:{url}}` ya da düz string — üçü de kabul edilir. */\nfunction readUrl(result: unknown): string | null {\n if (typeof result === 'string') return result || null;\n\n if (result && typeof result === 'object') {\n const record = result as { url?: unknown; data?: { url?: unknown } };\n\n if (typeof record.url === 'string') return record.url;\n if (record.data && typeof record.data.url === 'string') return record.data.url;\n }\n\n return null;\n}\n\nexport function createEmbed(options: EmbedOptions): EmbedHandle {\n const text = TEXT[options.language ?? 'tr'];\n const listeners = new Map<EmbedEvent, Set<Listener>>();\n\n let container: HTMLElement | null = null;\n let frame: HTMLIFrameElement | null = null;\n let messageHandler: ((event: MessageEvent) => void) | null = null;\n let theme: EmbedTheme = options.theme ?? 'auto';\n let destroyed = false;\n\n const emit = (event: EmbedEvent, payload?: unknown) => {\n listeners.get(event)?.forEach((fn) => {\n try {\n fn(payload);\n } catch (error) {\n console.warn('[signalbird]', error);\n }\n });\n };\n\n const clear = () => {\n if (messageHandler) {\n window.removeEventListener('message', messageHandler);\n messageHandler = null;\n }\n\n frame = null;\n\n if (container) container.textContent = '';\n };\n\n const status = (message: string, withRetry: boolean) => {\n if (!container) return;\n\n container.textContent = '';\n\n const box = document.createElement('div');\n box.setAttribute('data-signalbird-status', '');\n box.style.cssText =\n 'display:flex;align-items:center;justify-content:center;gap:12px;' +\n `min-height:${options.minHeight ?? 220}px;font:13px/1.5 system-ui,-apple-system,sans-serif;` +\n 'color:#6b7280;text-align:center;padding:24px;';\n\n const label = document.createElement('span');\n label.textContent = message;\n box.appendChild(label);\n\n if (withRetry) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = text.retry;\n button.style.cssText =\n 'border:1px solid currentColor;border-radius:8px;background:transparent;' +\n 'color:inherit;padding:4px 10px;font:inherit;cursor:pointer;';\n button.addEventListener('click', () => void render());\n box.appendChild(button);\n }\n\n container.appendChild(box);\n };\n\n /** Jetonu alır ve iframe'i kurar. Her çağrı YENİ jeton demektir. */\n const render = async (): Promise<void> => {\n if (!container || destroyed) return;\n\n clear();\n status(text.loading, false);\n\n const applied = resolveTheme(theme);\n let url: string | null = null;\n\n try {\n if (options.url) {\n // Elde hazır jeton varsa İLK kurulum onu kullanır: ev sahibi jetonu\n // zaten almış olabilir (ör. betiğin hangi kökenden yükleneceğini o\n // yanıttan öğrenir). Jeton tek kullanımlıktır, bu yüzden tüketilir;\n // sonraki `refresh()` çağrıları `mint` ister.\n url = options.url;\n options = { ...options, url: undefined };\n } else if (options.mint) {\n url = readUrl(\n await options.mint({ module: options.module, theme: applied, locale: options.locale }),\n );\n }\n } catch (error) {\n emit('error', error);\n status(error instanceof Error ? error.message : text.failed, true);\n\n return;\n }\n\n if (!url) {\n emit('error', new Error('EMBED_URL_MISSING'));\n status(text.expired, Boolean(options.mint));\n\n return;\n }\n\n // Tema/dil/vurgu adrese işlenir: gömülü ekran ev sahibiyle aynı görünsün.\n let target = url;\n\n try {\n const parsed = new URL(url);\n\n parsed.searchParams.set('theme', applied);\n if (options.locale) parsed.searchParams.set('locale', options.locale);\n if (options.accent) parsed.searchParams.set('accent', options.accent.replace(/^#/, ''));\n target = parsed.toString();\n } catch {\n // Göreli adres: olduğu gibi kullanılır.\n }\n\n const iframe = document.createElement('iframe');\n\n iframe.src = target;\n iframe.title = 'Signalbird';\n iframe.style.cssText = 'width:100%;border:0;display:block;';\n iframe.style.height = `${typeof options.height === 'number' ? options.height : options.minHeight ?? 640}px`;\n iframe.setAttribute('allow', 'clipboard-write; fullscreen; autoplay');\n /*\n * `allow-same-origin` ŞART: gömülü ekran jetonu KENDİ kökeninde oturuma\n * çevirir; sandbox onu kısarsa ekran hiç açılmaz. `allow-top-navigation`\n * VERİLMEZ — gömülü ekran ev sahibi panelin tamamını başka bir adrese\n * götüremesin. Ses (yeni mesaj) ve dosya yükleme için `allow-popups` ve\n * `allow-downloads` gerekir.\n */\n iframe.setAttribute(\n 'sandbox',\n 'allow-same-origin allow-scripts allow-forms allow-popups allow-downloads',\n );\n iframe.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');\n iframe.setAttribute('loading', 'lazy');\n\n if (options.className) iframe.className = options.className;\n\n container.textContent = '';\n container.appendChild(iframe);\n frame = iframe;\n\n // Gömülü ekran yüksekliğini ve hazır olduğunu bildirir. Gönderen KONTROL\n // EDİLİR (`event.source`): sayfadaki başka bir iframe bizim çerçevemizi\n // büyütemesin.\n messageHandler = (event: MessageEvent) => {\n if (!frame || event.source !== frame.contentWindow) return;\n\n const data = event.data as { type?: string; px?: number; module?: string } | null;\n\n if (!data || typeof data.type !== 'string') return;\n\n if (data.type === 'signalbird:ready') {\n emit('ready', data.module);\n\n return;\n }\n\n if (data.type === 'signalbird:height' && typeof data.px === 'number') {\n emit('height', data.px);\n\n if ((options.height ?? 'auto') === 'auto') {\n const px = Math.max(data.px, options.minHeight ?? 220);\n\n frame.style.height = `${px}px`;\n }\n }\n };\n\n window.addEventListener('message', messageHandler);\n };\n\n return {\n async mount(targetSelector) {\n const element =\n typeof targetSelector === 'string' ? document.querySelector(targetSelector) : targetSelector;\n\n if (!(element instanceof HTMLElement)) {\n throw new Error('Signalbird: gömme kabı bulunamadı — ' + String(targetSelector));\n }\n\n container = element;\n destroyed = false;\n\n await render();\n },\n\n refresh: () => render(),\n\n async setTheme(next) {\n theme = next;\n await render();\n },\n\n destroy() {\n destroyed = true;\n clear();\n listeners.clear();\n container = null;\n },\n\n on(event, handler) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(handler);\n },\n\n off(event, handler) {\n listeners.get(event)?.delete(handler);\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/embed/element.ts"],"names":[],"mappings":"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","file":"embed.mjs","sourcesContent":["/**\n * Gömme çekirdeği - çatısız, bağımlılıksız.\n *\n * Ev sahibi tarafında TEK satır:\n *\n * Signalbird.embed({ module: 'chat', mint }).mount('#sb-chat')\n *\n * Ne yapar:\n * • jetonu ev sahibinin sunucusundan ister (partner anahtarı tarayıcıya inmez)\n * • iframe'i kurar, tema/dil/vurgu rengini adrese işler\n * • gömülü ekranın `postMessage` ile bildirdiği yüksekliği uygular\n * • jeton süresi dolmuş/geçersizse anlaşılır bir hata ve \"yeniden dene\" çizer\n * • `destroy()` ile dinleyicileri bırakır (SPA'da sızıntı yok)\n *\n * NE YAPMAZ: modülün satın alınıp alınmadığına bakmaz. O kapı ev sahibinin\n * kendi satış kaydındadır ve `mint` çağrısı 403 dönerek söyler; SDK yalnız\n * mesajı gösterir.\n */\nimport type { EmbedEvent, EmbedHandle, EmbedOptions, EmbedTheme } from './types';\n\ntype Listener = (payload?: unknown) => void;\n\nconst TEXT = {\n tr: {\n loading: 'Yükleniyor…',\n failed: 'Ekran yüklenemedi.',\n expired: 'Bu bağlantının süresi doldu.',\n retry: 'Yeniden dene',\n },\n en: {\n loading: 'Loading…',\n failed: 'The screen could not be loaded.',\n expired: 'This link has expired.',\n retry: 'Try again',\n },\n} as const;\n\n/** Ev sahibi sayfanın kipi: açık talep > `data-theme`/`.dark` > işletim sistemi. */\nfunction resolveTheme(theme: EmbedTheme | undefined): 'light' | 'dark' {\n if (theme === 'light' || theme === 'dark') return theme;\n\n if (typeof document !== 'undefined') {\n const root = document.documentElement;\n\n if (root.classList.contains('dark') || root.dataset.theme === 'dark') return 'dark';\n if (root.classList.contains('light') || root.dataset.theme === 'light') return 'light';\n }\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n\n return 'light';\n}\n\n/** `{url}`, `{data:{url}}` ya da düz string - üçü de kabul edilir. */\nfunction readUrl(result: unknown): string | null {\n if (typeof result === 'string') return result || null;\n\n if (result && typeof result === 'object') {\n const record = result as { url?: unknown; data?: { url?: unknown } };\n\n if (typeof record.url === 'string') return record.url;\n if (record.data && typeof record.data.url === 'string') return record.data.url;\n }\n\n return null;\n}\n\nexport function createEmbed(options: EmbedOptions): EmbedHandle {\n const text = TEXT[options.language ?? 'tr'];\n const listeners = new Map<EmbedEvent, Set<Listener>>();\n\n let container: HTMLElement | null = null;\n let frame: HTMLIFrameElement | null = null;\n let messageHandler: ((event: MessageEvent) => void) | null = null;\n let theme: EmbedTheme = options.theme ?? 'auto';\n let destroyed = false;\n\n const emit = (event: EmbedEvent, payload?: unknown) => {\n listeners.get(event)?.forEach((fn) => {\n try {\n fn(payload);\n } catch (error) {\n console.warn('[signalbird]', error);\n }\n });\n };\n\n const clear = () => {\n if (messageHandler) {\n window.removeEventListener('message', messageHandler);\n messageHandler = null;\n }\n\n frame = null;\n\n if (container) container.textContent = '';\n };\n\n const status = (message: string, withRetry: boolean) => {\n if (!container) return;\n\n container.textContent = '';\n\n const box = document.createElement('div');\n box.setAttribute('data-signalbird-status', '');\n box.style.cssText =\n 'display:flex;align-items:center;justify-content:center;gap:12px;' +\n `min-height:${options.minHeight ?? 220}px;font:13px/1.5 system-ui,-apple-system,sans-serif;` +\n 'color:#6b7280;text-align:center;padding:24px;';\n\n const label = document.createElement('span');\n label.textContent = message;\n box.appendChild(label);\n\n if (withRetry) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = text.retry;\n button.style.cssText =\n 'border:1px solid currentColor;border-radius:8px;background:transparent;' +\n 'color:inherit;padding:4px 10px;font:inherit;cursor:pointer;';\n button.addEventListener('click', () => void render());\n box.appendChild(button);\n }\n\n container.appendChild(box);\n };\n\n /** Jetonu alır ve iframe'i kurar. Her çağrı YENİ jeton demektir. */\n const render = async (): Promise<void> => {\n if (!container || destroyed) return;\n\n clear();\n status(text.loading, false);\n\n const applied = resolveTheme(theme);\n let url: string | null = null;\n\n try {\n if (options.url) {\n // Elde hazır jeton varsa İLK kurulum onu kullanır: ev sahibi jetonu\n // zaten almış olabilir (ör. betiğin hangi kökenden yükleneceğini o\n // yanıttan öğrenir). Jeton tek kullanımlıktır, bu yüzden tüketilir;\n // sonraki `refresh()` çağrıları `mint` ister.\n url = options.url;\n options = { ...options, url: undefined };\n } else if (options.mint) {\n url = readUrl(\n await options.mint({ module: options.module, theme: applied, locale: options.locale }),\n );\n }\n } catch (error) {\n emit('error', error);\n status(error instanceof Error ? error.message : text.failed, true);\n\n return;\n }\n\n if (!url) {\n emit('error', new Error('EMBED_URL_MISSING'));\n status(text.expired, Boolean(options.mint));\n\n return;\n }\n\n // Tema/dil/vurgu adrese işlenir: gömülü ekran ev sahibiyle aynı görünsün.\n let target = url;\n\n try {\n const parsed = new URL(url);\n\n parsed.searchParams.set('theme', applied);\n if (options.locale) parsed.searchParams.set('locale', options.locale);\n if (options.accent) parsed.searchParams.set('accent', options.accent.replace(/^#/, ''));\n target = parsed.toString();\n } catch {\n // Göreli adres: olduğu gibi kullanılır.\n }\n\n const iframe = document.createElement('iframe');\n\n iframe.src = target;\n iframe.title = 'Signalbird';\n iframe.style.cssText = 'width:100%;border:0;display:block;';\n iframe.style.height = `${typeof options.height === 'number' ? options.height : options.minHeight ?? 640}px`;\n iframe.setAttribute('allow', 'clipboard-write; fullscreen; autoplay');\n /*\n * `allow-same-origin` ŞART: gömülü ekran jetonu KENDİ kökeninde oturuma\n * çevirir; sandbox onu kısarsa ekran hiç açılmaz. `allow-top-navigation`\n * VERİLMEZ - gömülü ekran ev sahibi panelin tamamını başka bir adrese\n * götüremesin. Ses (yeni mesaj) ve dosya yükleme için `allow-popups` ve\n * `allow-downloads` gerekir.\n */\n iframe.setAttribute(\n 'sandbox',\n 'allow-same-origin allow-scripts allow-forms allow-popups allow-downloads',\n );\n iframe.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');\n iframe.setAttribute('loading', 'lazy');\n\n if (options.className) iframe.className = options.className;\n\n container.textContent = '';\n container.appendChild(iframe);\n frame = iframe;\n\n // Gömülü ekran yüksekliğini ve hazır olduğunu bildirir. Gönderen KONTROL\n // EDİLİR (`event.source`): sayfadaki başka bir iframe bizim çerçevemizi\n // büyütemesin.\n messageHandler = (event: MessageEvent) => {\n if (!frame || event.source !== frame.contentWindow) return;\n\n const data = event.data as { type?: string; px?: number; module?: string } | null;\n\n if (!data || typeof data.type !== 'string') return;\n\n if (data.type === 'signalbird:ready') {\n emit('ready', data.module);\n\n return;\n }\n\n if (data.type === 'signalbird:height' && typeof data.px === 'number') {\n emit('height', data.px);\n\n if ((options.height ?? 'auto') === 'auto') {\n const px = Math.max(data.px, options.minHeight ?? 220);\n\n frame.style.height = `${px}px`;\n }\n }\n };\n\n window.addEventListener('message', messageHandler);\n };\n\n return {\n async mount(targetSelector) {\n const element =\n typeof targetSelector === 'string' ? document.querySelector(targetSelector) : targetSelector;\n\n if (!(element instanceof HTMLElement)) {\n throw new Error('Signalbird: gömme kabı bulunamadı - ' + String(targetSelector));\n }\n\n container = element;\n destroyed = false;\n\n await render();\n },\n\n refresh: () => render(),\n\n async setTheme(next) {\n theme = next;\n await render();\n },\n\n destroy() {\n destroyed = true;\n clear();\n listeners.clear();\n container = null;\n },\n\n on(event, handler) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(handler);\n },\n\n off(event, handler) {\n listeners.get(event)?.delete(handler);\n },\n };\n}\n"]}
|