@kitbase/messaging 0.1.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 +209 -0
- package/dist/cdn.js +299 -0
- package/dist/index.cjs +949 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +320 -0
- package/dist/index.d.ts +320 -0
- package/dist/index.js +915 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/api.ts","../src/styles.ts","../src/renderer.ts","../src/client.ts"],"sourcesContent":["// Main client\nexport { Messaging, init, getInstance } from './client.js';\n\n// Types\nexport type {\n MessagingConfig,\n InAppMessage,\n MessageType,\n MessageButton,\n GetMessagesOptions,\n SubscribeOptions,\n} from './types.js';\n\n// Errors\nexport {\n MessagingError,\n ApiError,\n AuthenticationError,\n ValidationError,\n TimeoutError,\n} from './errors.js';\n","/**\n * Base error class for Messaging SDK errors\n */\nexport class MessagingError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MessagingError';\n Object.setPrototypeOf(this, MessagingError.prototype);\n }\n}\n\n/**\n * Error thrown when API authentication fails\n */\nexport class AuthenticationError extends MessagingError {\n constructor(message = 'Invalid API key') {\n super(message);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Error thrown when the API request fails\n */\nexport class ApiError extends MessagingError {\n public readonly statusCode: number;\n public readonly response?: unknown;\n\n constructor(message: string, statusCode: number, response?: unknown) {\n super(message);\n this.name = 'ApiError';\n this.statusCode = statusCode;\n this.response = response;\n Object.setPrototypeOf(this, ApiError.prototype);\n }\n}\n\n/**\n * Error thrown when request validation fails\n */\nexport class ValidationError extends MessagingError {\n public readonly field?: string;\n\n constructor(message: string, field?: string) {\n super(message);\n this.name = 'ValidationError';\n this.field = field;\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\n/**\n * Error thrown when a request times out\n */\nexport class TimeoutError extends MessagingError {\n constructor(message = 'Request timed out') {\n super(message);\n this.name = 'TimeoutError';\n Object.setPrototypeOf(this, TimeoutError.prototype);\n }\n}\n","import type { InAppMessage, MessageType, GetMessagesOptions } from './types.js';\nimport {\n ApiError,\n AuthenticationError,\n TimeoutError,\n} from './errors.js';\n\nconst DEFAULT_BASE_URL = 'https://api.kitbase.dev';\nconst TIMEOUT = 30000;\n\n/** Raw API response shape (internal) */\ninterface SdkInAppMessageResponse {\n id: string;\n title: string;\n message: string;\n showOnce: boolean;\n messageType: string;\n channelName: string;\n imageUrl?: string;\n actionButtonText?: string;\n actionButtonUrl?: string;\n actionButtonColor?: string;\n actionButtonTextColor?: string;\n secondaryButtonText?: string;\n secondaryButtonUrl?: string;\n secondaryButtonColor?: string;\n secondaryButtonTextColor?: string;\n backgroundColor?: string;\n startDate?: string;\n endDate?: string;\n}\n\n/**\n * Low-level HTTP client for the in-app messages API.\n * @internal\n */\nexport class MessagingApi {\n private readonly baseUrl: string;\n\n constructor(private readonly sdkKey: string, baseUrl?: string) {\n this.baseUrl = (baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n }\n\n async getMessages(options?: GetMessagesOptions): Promise<InAppMessage[]> {\n const params: Record<string, string> = {};\n if (options?.userId) params.userId = options.userId;\n if (options?.metadata) params.metadata = JSON.stringify(options.metadata);\n\n const response = await this.get<{ messages: SdkInAppMessageResponse[] }>(\n '/sdk/v1/in-app-messages',\n params,\n );\n\n return response.messages.map(toInAppMessage);\n }\n\n async markViewed(messageId: string, userId: string): Promise<void> {\n await this.post('/sdk/v1/in-app-messages/views', { messageId, userId });\n }\n\n // ── HTTP ──────────────────────────────────────────────────────\n\n private async get<T>(endpoint: string, params?: Record<string, string>): Promise<T> {\n let url = `${this.baseUrl}${endpoint}`;\n if (params && Object.keys(params).length > 0) {\n const qs = Object.entries(params)\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)\n .join('&');\n url += `?${qs}`;\n }\n\n const controller = new AbortController();\n const tid = setTimeout(() => controller.abort(), TIMEOUT);\n\n try {\n const res = await fetch(url, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json', 'x-sdk-key': this.sdkKey },\n signal: controller.signal,\n });\n clearTimeout(tid);\n if (!res.ok) this.throwError(res, await this.parseBody(res));\n return (await res.json()) as T;\n } catch (err) {\n clearTimeout(tid);\n if (err instanceof Error && err.name === 'AbortError') throw new TimeoutError();\n throw err;\n }\n }\n\n private async post(endpoint: string, body: unknown): Promise<void> {\n const controller = new AbortController();\n const tid = setTimeout(() => controller.abort(), TIMEOUT);\n\n try {\n const res = await fetch(`${this.baseUrl}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'x-sdk-key': this.sdkKey },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n clearTimeout(tid);\n if (!res.ok) this.throwError(res, await this.parseBody(res));\n } catch (err) {\n clearTimeout(tid);\n if (err instanceof Error && err.name === 'AbortError') throw new TimeoutError();\n throw err;\n }\n }\n\n private throwError(res: Response, body: unknown): never {\n if (res.status === 401) throw new AuthenticationError();\n let msg = res.statusText;\n if (body && typeof body === 'object') {\n if ('message' in body) msg = String((body as any).message);\n else if ('error' in body) msg = String((body as any).error);\n }\n throw new ApiError(msg, res.status, body);\n }\n\n private async parseBody(res: Response): Promise<unknown> {\n try { return await res.json(); } catch { return null; }\n }\n}\n\n// ── Response mapping ────────────────────────────────────────────\n\nfunction toInAppMessage(raw: SdkInAppMessageResponse): InAppMessage {\n const msg: InAppMessage = {\n id: raw.id,\n title: raw.title,\n body: raw.message,\n showOnce: raw.showOnce,\n type: raw.messageType as MessageType,\n channel: raw.channelName || null,\n imageUrl: raw.imageUrl,\n backgroundColor: raw.backgroundColor,\n startDate: raw.startDate,\n endDate: raw.endDate,\n };\n\n if (raw.actionButtonText) {\n msg.actionButton = {\n text: raw.actionButtonText,\n url: raw.actionButtonUrl!,\n color: raw.actionButtonColor,\n textColor: raw.actionButtonTextColor,\n };\n }\n\n if (raw.secondaryButtonText) {\n msg.secondaryButton = {\n text: raw.secondaryButtonText,\n url: raw.secondaryButtonUrl!,\n color: raw.secondaryButtonColor,\n textColor: raw.secondaryButtonTextColor,\n };\n }\n\n return msg;\n}\n","/** Scoped CSS injected into the shadow DOM */\nexport const STYLES = /* css */ `\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;\n font-size: 14px;\n line-height: 1.5;\n color: #1a1a1a;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n*, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n/* ============================== Overlay ============================== */\n\n.kb-overlay {\n position: fixed;\n inset: 0;\n z-index: 999999;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 16px;\n animation: kb-fade-in 200ms ease-out;\n}\n.kb-overlay.kb-exit {\n animation: kb-fade-out 150ms ease-in forwards;\n}\n\n/* ============================== Modal ============================== */\n\n.kb-modal {\n position: relative;\n background: #fff;\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n max-width: 480px;\n width: 100%;\n overflow: hidden;\n animation: kb-scale-in 200ms ease-out;\n}\n.kb-overlay.kb-exit .kb-modal {\n animation: kb-scale-out 150ms ease-in forwards;\n}\n\n/* ============================== Banner ============================== */\n\n.kb-banner-container {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n z-index: 999998;\n display: flex;\n flex-direction: column;\n pointer-events: none;\n}\n\n.kb-banner {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 12px 20px;\n background: #4F46E5;\n color: #fff;\n pointer-events: auto;\n animation: kb-slide-down 250ms ease-out;\n}\n.kb-banner.kb-exit {\n animation: kb-slide-up-exit 150ms ease-in forwards;\n}\n.kb-banner .kb-content {\n flex: 1;\n min-width: 0;\n}\n.kb-banner .kb-title {\n font-weight: 600;\n font-size: 14px;\n}\n.kb-banner .kb-body {\n font-size: 13px;\n opacity: 0.9;\n color: inherit;\n margin: 0;\n}\n.kb-banner .kb-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n.kb-banner .kb-btn-action {\n background: rgba(255,255,255,0.2);\n color: #fff;\n}\n.kb-banner .kb-btn-secondary {\n background: transparent;\n color: rgba(255,255,255,0.8);\n}\n.kb-banner .kb-close {\n position: static;\n background: rgba(255,255,255,0.15);\n color: #fff;\n}\n.kb-banner .kb-close:hover {\n background: rgba(255,255,255,0.25);\n}\n\n/* ============================== Card ============================== */\n\n.kb-card-container {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 999997;\n display: flex;\n flex-direction: column;\n gap: 12px;\n max-width: 360px;\n pointer-events: none;\n}\n\n.kb-card {\n position: relative;\n background: #fff;\n border-radius: 16px;\n box-shadow: 0 10px 25px -5px rgba(0,0,0,0.1), 0 8px 10px -6px rgba(0,0,0,0.1);\n overflow: hidden;\n pointer-events: auto;\n animation: kb-slide-up 250ms ease-out;\n}\n.kb-card.kb-exit {\n animation: kb-slide-down-exit 150ms ease-in forwards;\n}\n\n/* ============================== Image (fullscreen) ============================== */\n\n.kb-image-msg {\n position: relative;\n max-width: 600px;\n width: 100%;\n animation: kb-scale-in 200ms ease-out;\n}\n.kb-overlay.kb-exit .kb-image-msg {\n animation: kb-scale-out 150ms ease-in forwards;\n}\n.kb-image-msg > img {\n display: block;\n width: 100%;\n border-radius: 16px;\n}\n.kb-image-msg .kb-buttons {\n margin-top: 12px;\n justify-content: center;\n}\n\n/* ============================== Shared ============================== */\n\n.kb-close {\n position: absolute;\n top: 8px;\n right: 8px;\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0,0,0,0.06);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n font-size: 18px;\n line-height: 1;\n color: #666;\n transition: background 150ms, color 150ms;\n z-index: 1;\n}\n.kb-close:hover {\n background: rgba(0,0,0,0.12);\n color: #333;\n}\n.kb-overlay .kb-close {\n background: rgba(255,255,255,0.15);\n color: #fff;\n}\n.kb-overlay .kb-close:hover {\n background: rgba(255,255,255,0.25);\n}\n\n.kb-msg-image {\n display: block;\n width: 100%;\n}\n\n.kb-content {\n padding: 20px;\n}\n\n.kb-title {\n font-size: 18px;\n font-weight: 600;\n line-height: 1.3;\n margin-bottom: 6px;\n}\n\n.kb-body {\n font-size: 14px;\n color: #555;\n line-height: 1.6;\n margin-bottom: 16px;\n white-space: pre-wrap;\n}\n\n.kb-buttons {\n display: flex;\n gap: 8px;\n}\n\n.kb-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 10px 20px;\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n text-decoration: none;\n transition: opacity 150ms;\n font-family: inherit;\n line-height: 1;\n}\n.kb-btn:hover {\n opacity: 0.88;\n}\n\n.kb-btn-action {\n background: #4F46E5;\n color: #fff;\n}\n\n.kb-btn-secondary {\n background: #f3f4f6;\n color: #374151;\n}\n\n/* ============================== Animations ============================== */\n\n@keyframes kb-fade-in {\n from { opacity: 0 } to { opacity: 1 }\n}\n@keyframes kb-fade-out {\n from { opacity: 1 } to { opacity: 0 }\n}\n@keyframes kb-scale-in {\n from { transform: scale(0.95); opacity: 0 }\n to { transform: scale(1); opacity: 1 }\n}\n@keyframes kb-scale-out {\n from { transform: scale(1); opacity: 1 }\n to { transform: scale(0.95); opacity: 0 }\n}\n@keyframes kb-slide-down {\n from { transform: translateY(-100%) }\n to { transform: translateY(0) }\n}\n@keyframes kb-slide-up-exit {\n from { transform: translateY(0) }\n to { transform: translateY(-100%) }\n}\n@keyframes kb-slide-up {\n from { transform: translateY(20px); opacity: 0 }\n to { transform: translateY(0); opacity: 1 }\n}\n@keyframes kb-slide-down-exit {\n from { transform: translateY(0); opacity: 1 }\n to { transform: translateY(20px); opacity: 0 }\n}\n\n/* ============================== Responsive ============================== */\n\n@media (max-width: 480px) {\n .kb-card-container {\n left: 12px;\n right: 12px;\n bottom: 12px;\n max-width: none;\n }\n .kb-modal {\n max-width: none;\n }\n}\n`;\n","import type { InAppMessage, MessageButton } from './types.js';\nimport { STYLES } from './styles.js';\n\nexport interface RendererCallbacks {\n onShow: (message: InAppMessage) => void;\n onDismiss: (message: InAppMessage) => void;\n onAction: (message: InAppMessage, button: MessageButton) => void | false;\n}\n\n/**\n * Renders in-app messages into a shadow DOM container.\n * Handles stacking for banners (top) and cards (bottom-right),\n * and overlays for modals and images.\n * @internal\n */\nexport class MessageRenderer {\n private host: HTMLElement;\n private shadow: ShadowRoot;\n private bannerContainer: HTMLElement;\n private cardContainer: HTMLElement;\n private displayed = new Map<string, { element: HTMLElement; message: InAppMessage }>();\n\n constructor(private callbacks: RendererCallbacks) {\n this.host = document.createElement('div');\n this.host.id = 'kitbase-messaging';\n document.body.appendChild(this.host);\n\n this.shadow = this.host.attachShadow({ mode: 'open' });\n\n // Inject styles\n const style = document.createElement('style');\n style.textContent = STYLES;\n this.shadow.appendChild(style);\n\n // Persistent containers for stackable types\n this.bannerContainer = document.createElement('div');\n this.bannerContainer.className = 'kb-banner-container';\n this.shadow.appendChild(this.bannerContainer);\n\n this.cardContainer = document.createElement('div');\n this.cardContainer.className = 'kb-card-container';\n this.shadow.appendChild(this.cardContainer);\n }\n\n /**\n * Reconcile: add new messages, remove stale ones.\n * Idempotent — calling with the same list is a no-op.\n */\n update(messages: InAppMessage[]): void {\n const incoming = new Set(messages.map((m) => m.id));\n\n // Remove messages no longer in the response\n for (const [id] of this.displayed) {\n if (!incoming.has(id)) {\n this.removeMessage(id);\n }\n }\n\n // Add new messages\n for (const msg of messages) {\n if (!this.displayed.has(msg.id)) {\n this.renderMessage(msg);\n }\n }\n }\n\n /** Programmatically dismiss a message (with exit animation). */\n dismiss(messageId: string): void {\n this.removeMessage(messageId);\n }\n\n /** Remove all rendered messages immediately. */\n clear(): void {\n for (const [id] of this.displayed) {\n const entry = this.displayed.get(id);\n if (entry) entry.element.remove();\n }\n this.displayed.clear();\n }\n\n /** Remove the shadow host from the DOM entirely. */\n destroy(): void {\n this.clear();\n this.host.remove();\n }\n\n // ── Rendering ─────────────────────────────────────────────────\n\n private renderMessage(msg: InAppMessage): void {\n let element: HTMLElement;\n\n switch (msg.type) {\n case 'banner':\n element = this.renderBanner(msg);\n this.bannerContainer.appendChild(element);\n break;\n case 'card':\n element = this.renderCard(msg);\n this.cardContainer.appendChild(element);\n break;\n case 'image':\n element = this.renderImageOverlay(msg);\n this.shadow.appendChild(element);\n break;\n case 'modal':\n default:\n element = this.renderModal(msg);\n this.shadow.appendChild(element);\n break;\n }\n\n this.displayed.set(msg.id, { element, message: msg });\n this.callbacks.onShow(msg);\n }\n\n private renderModal(msg: InAppMessage): HTMLElement {\n const overlay = this.el('div', 'kb-overlay');\n\n const modal = this.el('div', 'kb-modal');\n if (msg.backgroundColor) modal.style.background = msg.backgroundColor;\n\n modal.appendChild(this.closeButton(msg));\n\n if (msg.imageUrl) {\n const img = document.createElement('img');\n img.className = 'kb-msg-image';\n img.src = msg.imageUrl;\n img.alt = '';\n modal.appendChild(img);\n }\n\n const content = this.el('div', 'kb-content');\n content.appendChild(this.titleEl(msg.title));\n if (msg.body) content.appendChild(this.bodyEl(msg.body));\n content.appendChild(this.buttonsEl(msg));\n modal.appendChild(content);\n\n // Click overlay backdrop to dismiss\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) this.handleDismiss(msg);\n });\n\n overlay.appendChild(modal);\n return overlay;\n }\n\n private renderBanner(msg: InAppMessage): HTMLElement {\n const banner = this.el('div', 'kb-banner');\n if (msg.backgroundColor) {\n banner.style.background = msg.backgroundColor;\n }\n\n const content = this.el('div', 'kb-content');\n content.appendChild(this.titleEl(msg.title));\n if (msg.body) content.appendChild(this.bodyEl(msg.body));\n banner.appendChild(content);\n\n const actions = this.el('div', 'kb-actions');\n if (msg.actionButton) {\n actions.appendChild(this.btnEl(msg, msg.actionButton, 'kb-btn-action'));\n }\n if (msg.secondaryButton) {\n actions.appendChild(this.btnEl(msg, msg.secondaryButton, 'kb-btn-secondary'));\n }\n actions.appendChild(this.closeButton(msg));\n banner.appendChild(actions);\n\n return banner;\n }\n\n private renderCard(msg: InAppMessage): HTMLElement {\n const card = this.el('div', 'kb-card');\n if (msg.backgroundColor) card.style.background = msg.backgroundColor;\n\n card.appendChild(this.closeButton(msg));\n\n if (msg.imageUrl) {\n const img = document.createElement('img');\n img.className = 'kb-msg-image';\n img.src = msg.imageUrl;\n img.alt = '';\n card.appendChild(img);\n }\n\n const content = this.el('div', 'kb-content');\n content.appendChild(this.titleEl(msg.title));\n if (msg.body) content.appendChild(this.bodyEl(msg.body));\n content.appendChild(this.buttonsEl(msg));\n card.appendChild(content);\n\n return card;\n }\n\n private renderImageOverlay(msg: InAppMessage): HTMLElement {\n const overlay = this.el('div', 'kb-overlay');\n\n const container = this.el('div', 'kb-image-msg');\n container.appendChild(this.closeButton(msg));\n\n if (msg.imageUrl) {\n const img = document.createElement('img');\n img.src = msg.imageUrl;\n img.alt = msg.title;\n container.appendChild(img);\n }\n\n const buttons = this.buttonsEl(msg);\n if (buttons.childElementCount > 0) {\n container.appendChild(buttons);\n }\n\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) this.handleDismiss(msg);\n });\n\n overlay.appendChild(container);\n return overlay;\n }\n\n // ── Shared elements ───────────────────────────────────────────\n\n private titleEl(text: string): HTMLElement {\n const el = this.el('div', 'kb-title');\n el.textContent = text;\n return el;\n }\n\n private bodyEl(text: string): HTMLElement {\n const el = this.el('div', 'kb-body');\n el.textContent = text;\n return el;\n }\n\n private buttonsEl(msg: InAppMessage): HTMLElement {\n const wrap = this.el('div', 'kb-buttons');\n if (msg.actionButton) {\n wrap.appendChild(this.btnEl(msg, msg.actionButton, 'kb-btn-action'));\n }\n if (msg.secondaryButton) {\n wrap.appendChild(this.btnEl(msg, msg.secondaryButton, 'kb-btn-secondary'));\n }\n return wrap;\n }\n\n private btnEl(\n msg: InAppMessage,\n button: MessageButton,\n className: string,\n ): HTMLElement {\n const btn = document.createElement('button');\n btn.className = `kb-btn ${className}`;\n btn.textContent = button.text;\n if (button.color) btn.style.background = button.color;\n if (button.textColor) btn.style.color = button.textColor;\n\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.handleAction(msg, button);\n });\n\n return btn;\n }\n\n private closeButton(msg: InAppMessage): HTMLElement {\n const btn = document.createElement('button');\n btn.className = 'kb-close';\n btn.innerHTML = '✕';\n btn.setAttribute('aria-label', 'Close');\n\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.handleDismiss(msg);\n });\n\n return btn;\n }\n\n // ── Event handling ────────────────────────────────────────────\n\n private handleDismiss(msg: InAppMessage): void {\n const entry = this.displayed.get(msg.id);\n if (!entry) return;\n this.animateOut(entry.element, msg);\n }\n\n private handleAction(msg: InAppMessage, button: MessageButton): void {\n const result = this.callbacks.onAction(msg, button);\n\n // Navigate unless prevented\n if (result !== false && button.url) {\n window.open(button.url, '_blank', 'noopener');\n }\n\n // Dismiss after action\n const entry = this.displayed.get(msg.id);\n if (entry) {\n this.animateOut(entry.element, msg);\n }\n }\n\n // ── Animation + cleanup ───────────────────────────────────────\n\n private removeMessage(id: string): void {\n const entry = this.displayed.get(id);\n if (!entry) return;\n this.animateOut(entry.element, entry.message);\n }\n\n private animateOut(element: HTMLElement, msg: InAppMessage): void {\n if (element.classList.contains('kb-exit')) return; // already exiting\n element.classList.add('kb-exit');\n\n const cleanup = () => {\n element.remove();\n this.displayed.delete(msg.id);\n this.callbacks.onDismiss(msg);\n };\n\n element.addEventListener('animationend', cleanup, { once: true });\n // Fallback if animation doesn't fire (e.g. prefers-reduced-motion)\n setTimeout(cleanup, 300);\n }\n\n // ── Helpers ───────────────────────────────────────────────────\n\n private el(tag: string, className: string): HTMLElement {\n const el = document.createElement(tag);\n el.className = className;\n return el;\n }\n}\n","import type {\n MessagingConfig,\n InAppMessage,\n GetMessagesOptions,\n SubscribeOptions,\n} from './types.js';\nimport { ValidationError } from './errors.js';\nimport { MessagingApi } from './api.js';\nimport { MessageRenderer } from './renderer.js';\n\nconst DEFAULT_POLL_INTERVAL = 60000;\n\n/**\n * Singleton instance managed by `init()` / `getInstance()`.\n */\nlet _instance: Messaging | null = null;\n\n/**\n * Initialize the Kitbase In-App Messaging SDK.\n *\n * Creates a singleton instance that is used for all messaging.\n * Call this once at the top of your application entry point.\n *\n * @param config - SDK configuration\n * @returns The Messaging instance\n *\n * @example\n * ```typescript\n * import { init } from '@kitbase/messaging';\n *\n * const messaging = init({\n * sdkKey: 'your-api-key',\n * userId: currentUser.id,\n * metadata: { plan: 'pro' },\n * });\n * ```\n */\nexport function init(config: MessagingConfig): Messaging {\n if (_instance) {\n _instance.close();\n }\n _instance = new Messaging(config);\n return _instance;\n}\n\n/**\n * Get the current Messaging singleton instance.\n *\n * @returns The instance, or null if `init()` has not been called\n */\nexport function getInstance(): Messaging | null {\n return _instance;\n}\n\n/**\n * Kitbase In-App Messaging SDK\n *\n * Fetches targeted in-app messages and renders them directly in the page.\n * Supports modals, banners, cards, and full-screen images with automatic\n * stacking.\n *\n * @example Using init (recommended)\n * ```typescript\n * import { init } from '@kitbase/messaging';\n *\n * const messaging = init({\n * sdkKey: 'your-api-key',\n * metadata: { plan: 'pro' },\n * onAction: (msg, btn) => {\n * console.log('User clicked:', btn.text);\n * },\n * });\n *\n * // Later: clean up\n * messaging.close();\n * ```\n *\n * @example CDN (zero-config)\n * ```html\n * <script>\n * window.KITBASE_MESSAGING = { sdkKey: 'your-api-key' };\n * </script>\n * <script src=\"https://unpkg.com/@kitbase/messaging/dist/cdn.js\"></script>\n * <!-- Messages appear automatically! -->\n * ```\n *\n * @example Data-only (no rendering)\n * ```typescript\n * const messaging = init({\n * sdkKey: 'your-api-key',\n * autoShow: false,\n * });\n *\n * const messages = await messaging.getMessages();\n * // render messages yourself\n * ```\n */\nexport class Messaging {\n private api: MessagingApi;\n private renderer: MessageRenderer | null = null;\n private config: MessagingConfig;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private dismissed = new Set<string>();\n private subscriptionTimers = new Set<ReturnType<typeof setInterval>>();\n private pendingPoll = false;\n private visibilityHandler: (() => void) | null = null;\n\n private userId: string | undefined;\n\n constructor(config: MessagingConfig) {\n if (!config.sdkKey) {\n throw new ValidationError('SDK key is required', 'sdkKey');\n }\n\n this.config = config;\n this.userId = config.userId;\n this.api = new MessagingApi(config.sdkKey, config.baseUrl);\n\n if (config.autoShow !== false && typeof window !== 'undefined') {\n this.start();\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────\n\n /**\n * Start fetching and rendering messages.\n * Called automatically unless `autoShow: false`.\n */\n start(): void {\n if (typeof window === 'undefined') return;\n if (this.renderer) return; // already started\n\n this.renderer = new MessageRenderer({\n onShow: (msg) => {\n this.config.onShow?.(msg);\n },\n onDismiss: (msg) => {\n this.dismissed.add(msg.id);\n this.config.onDismiss?.(msg);\n },\n onAction: (msg, btn) => {\n return this.config.onAction?.(msg, btn);\n },\n });\n\n // Fetch immediately\n this.poll();\n\n // Set up polling\n const interval = this.config.pollInterval ?? DEFAULT_POLL_INTERVAL;\n if (interval > 0) {\n this.pollTimer = setInterval(() => this.poll(), interval);\n }\n\n // Pause polling when tab is hidden, resume when visible\n this.visibilityHandler = () => {\n if (document.visibilityState === 'visible' && this.pendingPoll) {\n this.pendingPoll = false;\n this.poll();\n }\n };\n document.addEventListener('visibilitychange', this.visibilityHandler);\n }\n\n /**\n * Stop polling and remove all rendered messages.\n */\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n if (this.visibilityHandler) {\n document.removeEventListener('visibilitychange', this.visibilityHandler);\n this.visibilityHandler = null;\n }\n this.pendingPoll = false;\n this.renderer?.destroy();\n this.renderer = null;\n }\n\n /**\n * Stop everything and remove all rendered UI.\n */\n close(): void {\n this.stop();\n for (const tid of this.subscriptionTimers) {\n clearInterval(tid);\n }\n this.subscriptionTimers.clear();\n this.dismissed.clear();\n }\n\n // ── User identity ────────────────────────────────────────────\n\n /**\n * Set the current user ID.\n * Triggers an immediate re-fetch so show-once messages that the user\n * has already viewed are filtered out.\n */\n identify(userId: string): void {\n this.userId = userId;\n this.poll();\n }\n\n /**\n * Clear the current user ID and reset dismissed messages.\n * Call this on logout.\n */\n reset(): void {\n this.userId = undefined;\n this.dismissed.clear();\n this.poll();\n }\n\n /**\n * Record that the current user has viewed a message.\n * The message is optimistically removed from the UI.\n *\n * @throws {ValidationError} When no user ID has been set\n * @throws {ApiError} When the API returns an error\n */\n async markViewed(messageId: string): Promise<void> {\n if (!this.userId) {\n throw new ValidationError(\n 'User ID is required to mark a message as viewed. Call identify() first.',\n 'userId',\n );\n }\n this.dismissed.add(messageId);\n this.renderer?.dismiss(messageId);\n await this.api.markViewed(messageId, this.userId);\n }\n\n // ── Data-only methods ─────────────────────────────────────────\n\n /**\n * Fetch active messages without rendering.\n * Use this when `autoShow: false` or for custom rendering.\n *\n * @param options - Metadata for targeting evaluation\n * @throws {AuthenticationError} When the API key is invalid\n * @throws {ApiError} When the API returns an error\n * @throws {TimeoutError} When the request times out\n */\n async getMessages(options?: GetMessagesOptions): Promise<InAppMessage[]> {\n return this.api.getMessages(options);\n }\n\n /**\n * Subscribe to messages with polling (data-only, no rendering).\n * Returns an unsubscribe function.\n *\n * @example\n * ```typescript\n * const unsub = messaging.subscribe(\n * (messages) => renderMyUI(messages),\n * { pollInterval: 30_000 },\n * );\n *\n * // Later\n * unsub();\n * ```\n */\n subscribe(\n callback: (messages: InAppMessage[]) => void,\n options?: SubscribeOptions,\n ): () => void {\n const interval = options?.pollInterval ?? DEFAULT_POLL_INTERVAL;\n let active = true;\n\n const run = async () => {\n if (!active) return;\n try {\n const msgs = await this.api.getMessages(options);\n if (active) callback(msgs);\n } catch {\n /* skip failed polls */\n }\n };\n\n run();\n const tid = setInterval(run, interval);\n this.subscriptionTimers.add(tid);\n\n return () => {\n active = false;\n clearInterval(tid);\n this.subscriptionTimers.delete(tid);\n };\n }\n\n // ── Internal ──────────────────────────────────────────────────\n\n private async poll(): Promise<void> {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') {\n this.pendingPoll = true;\n return;\n }\n\n try {\n const messages = await this.api.getMessages({\n userId: this.userId,\n metadata: this.config.metadata,\n });\n\n // Filter out messages dismissed in this session\n const visible = messages.filter((m) => !this.dismissed.has(m.id));\n\n this.renderer?.update(visible);\n } catch {\n /* silently skip failed polls */\n }\n }\n}\n"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the Messaging SDK
|
|
3
|
+
*
|
|
4
|
+
* @example CDN / Script tag
|
|
5
|
+
* ```html
|
|
6
|
+
* <script>
|
|
7
|
+
* window.KITBASE_MESSAGING = { sdkKey: 'your-api-key' };
|
|
8
|
+
* </script>
|
|
9
|
+
* <script src="https://unpkg.com/@kitbase/messaging/dist/cdn.js"></script>
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @example NPM
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { Messaging } from '@kitbase/messaging';
|
|
15
|
+
*
|
|
16
|
+
* const messaging = new Messaging({
|
|
17
|
+
* sdkKey: 'your-api-key',
|
|
18
|
+
* metadata: { plan: 'pro' },
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
interface MessagingConfig {
|
|
23
|
+
/** Your Kitbase SDK key */
|
|
24
|
+
sdkKey: string;
|
|
25
|
+
/**
|
|
26
|
+
* Override the API base URL (for self-hosted instances).
|
|
27
|
+
* @default 'https://api.kitbase.dev'
|
|
28
|
+
*/
|
|
29
|
+
baseUrl?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Current user ID. When provided, show-once messages that the user
|
|
32
|
+
* has already viewed are excluded from results.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* new Messaging({
|
|
37
|
+
* sdkKey: '...',
|
|
38
|
+
* userId: currentUser.id,
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
userId?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Metadata key-value pairs for targeting evaluation.
|
|
45
|
+
* Only messages whose targeting conditions match this metadata
|
|
46
|
+
* will be returned.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* new Messaging({
|
|
51
|
+
* sdkKey: '...',
|
|
52
|
+
* metadata: { plan: 'free', country: 'US' },
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
metadata?: Record<string, string>;
|
|
57
|
+
/**
|
|
58
|
+
* How often to poll for new messages (milliseconds).
|
|
59
|
+
* Set to `0` to disable polling (fetch once on init only).
|
|
60
|
+
* @default 60000
|
|
61
|
+
*/
|
|
62
|
+
pollInterval?: number;
|
|
63
|
+
/**
|
|
64
|
+
* Automatically render messages in the page.
|
|
65
|
+
* Set to `false` to use data-only mode (fetch without rendering).
|
|
66
|
+
* @default true
|
|
67
|
+
*/
|
|
68
|
+
autoShow?: boolean;
|
|
69
|
+
/** Called when a message is displayed to the user. */
|
|
70
|
+
onShow?: (message: InAppMessage) => void;
|
|
71
|
+
/** Called when a message is dismissed (close button or after action). */
|
|
72
|
+
onDismiss?: (message: InAppMessage) => void;
|
|
73
|
+
/**
|
|
74
|
+
* Called when an action button is clicked.
|
|
75
|
+
* By default, the URL is opened in a new tab.
|
|
76
|
+
* Return `false` to prevent the default navigation.
|
|
77
|
+
*/
|
|
78
|
+
onAction?: (message: InAppMessage, button: MessageButton) => void | false;
|
|
79
|
+
}
|
|
80
|
+
/** Message display format */
|
|
81
|
+
type MessageType = 'modal' | 'banner' | 'card' | 'image';
|
|
82
|
+
/**
|
|
83
|
+
* A message action button with optional styling
|
|
84
|
+
*/
|
|
85
|
+
interface MessageButton {
|
|
86
|
+
/** Button label */
|
|
87
|
+
text: string;
|
|
88
|
+
/** URL to navigate to when clicked */
|
|
89
|
+
url: string;
|
|
90
|
+
/** Button background color (hex, e.g. '#4F46E5') */
|
|
91
|
+
color?: string;
|
|
92
|
+
/** Button text color (hex, e.g. '#FFFFFF') */
|
|
93
|
+
textColor?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* An in-app message
|
|
97
|
+
*/
|
|
98
|
+
interface InAppMessage {
|
|
99
|
+
/** Unique message ID */
|
|
100
|
+
id: string;
|
|
101
|
+
/** Message heading */
|
|
102
|
+
title: string;
|
|
103
|
+
/** Message body */
|
|
104
|
+
body: string;
|
|
105
|
+
/** If true, the message is hidden after the user views it once */
|
|
106
|
+
showOnce: boolean;
|
|
107
|
+
/** Display format */
|
|
108
|
+
type: MessageType;
|
|
109
|
+
/** Channel this message belongs to, or null */
|
|
110
|
+
channel: string | null;
|
|
111
|
+
/** Optional image URL */
|
|
112
|
+
imageUrl?: string;
|
|
113
|
+
/** Primary action button */
|
|
114
|
+
actionButton?: MessageButton;
|
|
115
|
+
/** Secondary action button (e.g. dismiss) */
|
|
116
|
+
secondaryButton?: MessageButton;
|
|
117
|
+
/** Background color (hex) */
|
|
118
|
+
backgroundColor?: string;
|
|
119
|
+
/** Scheduled start date (ISO-8601) */
|
|
120
|
+
startDate?: string;
|
|
121
|
+
/** Scheduled end date (ISO-8601) */
|
|
122
|
+
endDate?: string;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Options for fetching in-app messages
|
|
126
|
+
*/
|
|
127
|
+
interface GetMessagesOptions {
|
|
128
|
+
/** User ID for filtering already-viewed show-once messages */
|
|
129
|
+
userId?: string;
|
|
130
|
+
/** Metadata for targeting evaluation */
|
|
131
|
+
metadata?: Record<string, string>;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Options for subscribing to messages with polling
|
|
135
|
+
*/
|
|
136
|
+
interface SubscribeOptions extends GetMessagesOptions {
|
|
137
|
+
/**
|
|
138
|
+
* How often to poll for new messages (milliseconds).
|
|
139
|
+
* @default 60000
|
|
140
|
+
*/
|
|
141
|
+
pollInterval?: number;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Initialize the Kitbase In-App Messaging SDK.
|
|
146
|
+
*
|
|
147
|
+
* Creates a singleton instance that is used for all messaging.
|
|
148
|
+
* Call this once at the top of your application entry point.
|
|
149
|
+
*
|
|
150
|
+
* @param config - SDK configuration
|
|
151
|
+
* @returns The Messaging instance
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* import { init } from '@kitbase/messaging';
|
|
156
|
+
*
|
|
157
|
+
* const messaging = init({
|
|
158
|
+
* sdkKey: 'your-api-key',
|
|
159
|
+
* userId: currentUser.id,
|
|
160
|
+
* metadata: { plan: 'pro' },
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
declare function init(config: MessagingConfig): Messaging;
|
|
165
|
+
/**
|
|
166
|
+
* Get the current Messaging singleton instance.
|
|
167
|
+
*
|
|
168
|
+
* @returns The instance, or null if `init()` has not been called
|
|
169
|
+
*/
|
|
170
|
+
declare function getInstance(): Messaging | null;
|
|
171
|
+
/**
|
|
172
|
+
* Kitbase In-App Messaging SDK
|
|
173
|
+
*
|
|
174
|
+
* Fetches targeted in-app messages and renders them directly in the page.
|
|
175
|
+
* Supports modals, banners, cards, and full-screen images with automatic
|
|
176
|
+
* stacking.
|
|
177
|
+
*
|
|
178
|
+
* @example Using init (recommended)
|
|
179
|
+
* ```typescript
|
|
180
|
+
* import { init } from '@kitbase/messaging';
|
|
181
|
+
*
|
|
182
|
+
* const messaging = init({
|
|
183
|
+
* sdkKey: 'your-api-key',
|
|
184
|
+
* metadata: { plan: 'pro' },
|
|
185
|
+
* onAction: (msg, btn) => {
|
|
186
|
+
* console.log('User clicked:', btn.text);
|
|
187
|
+
* },
|
|
188
|
+
* });
|
|
189
|
+
*
|
|
190
|
+
* // Later: clean up
|
|
191
|
+
* messaging.close();
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example CDN (zero-config)
|
|
195
|
+
* ```html
|
|
196
|
+
* <script>
|
|
197
|
+
* window.KITBASE_MESSAGING = { sdkKey: 'your-api-key' };
|
|
198
|
+
* </script>
|
|
199
|
+
* <script src="https://unpkg.com/@kitbase/messaging/dist/cdn.js"></script>
|
|
200
|
+
* <!-- Messages appear automatically! -->
|
|
201
|
+
* ```
|
|
202
|
+
*
|
|
203
|
+
* @example Data-only (no rendering)
|
|
204
|
+
* ```typescript
|
|
205
|
+
* const messaging = init({
|
|
206
|
+
* sdkKey: 'your-api-key',
|
|
207
|
+
* autoShow: false,
|
|
208
|
+
* });
|
|
209
|
+
*
|
|
210
|
+
* const messages = await messaging.getMessages();
|
|
211
|
+
* // render messages yourself
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
declare class Messaging {
|
|
215
|
+
private api;
|
|
216
|
+
private renderer;
|
|
217
|
+
private config;
|
|
218
|
+
private pollTimer;
|
|
219
|
+
private dismissed;
|
|
220
|
+
private subscriptionTimers;
|
|
221
|
+
private pendingPoll;
|
|
222
|
+
private visibilityHandler;
|
|
223
|
+
private userId;
|
|
224
|
+
constructor(config: MessagingConfig);
|
|
225
|
+
/**
|
|
226
|
+
* Start fetching and rendering messages.
|
|
227
|
+
* Called automatically unless `autoShow: false`.
|
|
228
|
+
*/
|
|
229
|
+
start(): void;
|
|
230
|
+
/**
|
|
231
|
+
* Stop polling and remove all rendered messages.
|
|
232
|
+
*/
|
|
233
|
+
stop(): void;
|
|
234
|
+
/**
|
|
235
|
+
* Stop everything and remove all rendered UI.
|
|
236
|
+
*/
|
|
237
|
+
close(): void;
|
|
238
|
+
/**
|
|
239
|
+
* Set the current user ID.
|
|
240
|
+
* Triggers an immediate re-fetch so show-once messages that the user
|
|
241
|
+
* has already viewed are filtered out.
|
|
242
|
+
*/
|
|
243
|
+
identify(userId: string): void;
|
|
244
|
+
/**
|
|
245
|
+
* Clear the current user ID and reset dismissed messages.
|
|
246
|
+
* Call this on logout.
|
|
247
|
+
*/
|
|
248
|
+
reset(): void;
|
|
249
|
+
/**
|
|
250
|
+
* Record that the current user has viewed a message.
|
|
251
|
+
* The message is optimistically removed from the UI.
|
|
252
|
+
*
|
|
253
|
+
* @throws {ValidationError} When no user ID has been set
|
|
254
|
+
* @throws {ApiError} When the API returns an error
|
|
255
|
+
*/
|
|
256
|
+
markViewed(messageId: string): Promise<void>;
|
|
257
|
+
/**
|
|
258
|
+
* Fetch active messages without rendering.
|
|
259
|
+
* Use this when `autoShow: false` or for custom rendering.
|
|
260
|
+
*
|
|
261
|
+
* @param options - Metadata for targeting evaluation
|
|
262
|
+
* @throws {AuthenticationError} When the API key is invalid
|
|
263
|
+
* @throws {ApiError} When the API returns an error
|
|
264
|
+
* @throws {TimeoutError} When the request times out
|
|
265
|
+
*/
|
|
266
|
+
getMessages(options?: GetMessagesOptions): Promise<InAppMessage[]>;
|
|
267
|
+
/**
|
|
268
|
+
* Subscribe to messages with polling (data-only, no rendering).
|
|
269
|
+
* Returns an unsubscribe function.
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```typescript
|
|
273
|
+
* const unsub = messaging.subscribe(
|
|
274
|
+
* (messages) => renderMyUI(messages),
|
|
275
|
+
* { pollInterval: 30_000 },
|
|
276
|
+
* );
|
|
277
|
+
*
|
|
278
|
+
* // Later
|
|
279
|
+
* unsub();
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
subscribe(callback: (messages: InAppMessage[]) => void, options?: SubscribeOptions): () => void;
|
|
283
|
+
private poll;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Base error class for Messaging SDK errors
|
|
288
|
+
*/
|
|
289
|
+
declare class MessagingError extends Error {
|
|
290
|
+
constructor(message: string);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Error thrown when API authentication fails
|
|
294
|
+
*/
|
|
295
|
+
declare class AuthenticationError extends MessagingError {
|
|
296
|
+
constructor(message?: string);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Error thrown when the API request fails
|
|
300
|
+
*/
|
|
301
|
+
declare class ApiError extends MessagingError {
|
|
302
|
+
readonly statusCode: number;
|
|
303
|
+
readonly response?: unknown;
|
|
304
|
+
constructor(message: string, statusCode: number, response?: unknown);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Error thrown when request validation fails
|
|
308
|
+
*/
|
|
309
|
+
declare class ValidationError extends MessagingError {
|
|
310
|
+
readonly field?: string;
|
|
311
|
+
constructor(message: string, field?: string);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Error thrown when a request times out
|
|
315
|
+
*/
|
|
316
|
+
declare class TimeoutError extends MessagingError {
|
|
317
|
+
constructor(message?: string);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export { ApiError, AuthenticationError, type GetMessagesOptions, type InAppMessage, type MessageButton, type MessageType, Messaging, type MessagingConfig, MessagingError, type SubscribeOptions, TimeoutError, ValidationError, getInstance, init };
|