@churnback/sdk 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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/config.ts","../src/core/api.ts","../src/cancel-flow/styles.ts","../src/cancel-flow/steps.ts","../src/cancel-flow/modal.ts","../src/dunning/styles.ts","../src/dunning/banner.ts","../src/index.ts"],"sourcesContent":["export interface ChurnBackConfig {\n apiKey: string;\n apiBaseUrl?: string;\n}\n\nexport interface ResolvedConfig {\n apiKey: string;\n apiBaseUrl: string;\n}\n\nexport function resolveConfig(config: ChurnBackConfig): ResolvedConfig {\n return {\n apiKey: config.apiKey,\n apiBaseUrl: (config.apiBaseUrl || \"https://churnback.ai/api/sdk\").replace(/\\/$/, \"\"),\n };\n}\n","import type { ResolvedConfig } from \"./config\";\n\nexport interface FlowResponse {\n sessionId: string;\n steps: FlowStep[];\n style: Record<string, string>;\n}\n\nexport interface FlowStep {\n id: string;\n type: \"reason_survey\" | \"offer\" | \"custom_message\" | \"confirmation\";\n config: Record<string, unknown>;\n}\n\nexport interface SubmitPayload {\n sessionId: string;\n action: \"offer_accepted\" | \"cancelled\" | \"abandoned\";\n reason?: string;\n comment?: string;\n acceptedOffer?: Record<string, unknown>;\n}\n\nexport interface DunningResponse {\n hasFailedPayment: boolean;\n amountDueCents?: number;\n updatePaymentUrl?: string;\n bannerConfig?: {\n headline: string;\n body: string;\n ctaText: string;\n };\n}\n\nexport class ApiClient {\n constructor(private config: ResolvedConfig) {}\n\n async fetchCancelFlow(\n customerId: string,\n subscriptionId: string,\n priceId?: string\n ): Promise<FlowResponse> {\n const params = new URLSearchParams({\n customer_id: customerId,\n subscription_id: subscriptionId,\n });\n if (priceId) params.set(\"price_id\", priceId);\n\n const res = await fetch(`${this.config.apiBaseUrl}/cancel-flow?${params}`, {\n headers: { \"x-churnback-key\": this.config.apiKey },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error(body.error || `Failed to fetch cancel flow (${res.status})`);\n }\n\n return res.json();\n }\n\n async submitResult(payload: SubmitPayload): Promise<void> {\n const res = await fetch(`${this.config.apiBaseUrl}/submit`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-churnback-key\": this.config.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error(body.error || `Failed to submit result (${res.status})`);\n }\n }\n\n async checkDunning(customerId: string): Promise<DunningResponse> {\n const params = new URLSearchParams({ customer_id: customerId });\n\n const res = await fetch(`${this.config.apiBaseUrl}/dunning?${params}`, {\n headers: { \"x-churnback-key\": this.config.apiKey },\n });\n\n if (!res.ok) {\n return { hasFailedPayment: false };\n }\n\n return res.json();\n }\n}\n","export const MODAL_STYLES = `\n * { box-sizing: border-box; margin: 0; padding: 0; }\n\n .cb-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 999999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n animation: cb-fade-in 0.2s ease;\n }\n\n @keyframes cb-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n @keyframes cb-slide-up {\n from { transform: translateY(20px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n\n .cb-modal {\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 480px;\n width: 90%;\n max-height: 90vh;\n overflow-y: auto;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\n animation: cb-slide-up 0.3s ease;\n }\n\n .cb-headline {\n font-size: 22px;\n font-weight: 700;\n color: #1a1a1a;\n margin-bottom: 12px;\n line-height: 1.3;\n }\n\n .cb-body {\n font-size: 15px;\n color: #555;\n line-height: 1.6;\n margin-bottom: 20px;\n }\n\n .cb-reasons {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-bottom: 16px;\n }\n\n .cb-reason {\n padding: 12px 16px;\n border: 2px solid #e0e0e0;\n border-radius: 10px;\n cursor: pointer;\n font-size: 14px;\n color: #333;\n transition: all 0.15s ease;\n background: white;\n text-align: left;\n }\n\n .cb-reason:hover {\n border-color: #7c3aed;\n background: #f5f3ff;\n }\n\n .cb-reason.selected {\n border-color: #7c3aed;\n background: #f5f3ff;\n color: #7c3aed;\n font-weight: 500;\n }\n\n .cb-textarea {\n width: 100%;\n min-height: 80px;\n padding: 12px;\n border: 2px solid #e0e0e0;\n border-radius: 10px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n margin-bottom: 16px;\n outline: none;\n transition: border-color 0.15s ease;\n }\n\n .cb-textarea:focus {\n border-color: #7c3aed;\n }\n\n .cb-btn {\n display: block;\n width: 100%;\n padding: 12px 20px;\n border-radius: 10px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n border: none;\n transition: all 0.15s ease;\n margin-bottom: 8px;\n }\n\n .cb-btn-primary {\n background: #7c3aed;\n color: white;\n }\n\n .cb-btn-primary:hover {\n background: #6d28d9;\n }\n\n .cb-btn-danger {\n background: #ef4444;\n color: white;\n }\n\n .cb-btn-danger:hover {\n background: #dc2626;\n }\n\n .cb-btn-secondary {\n background: transparent;\n color: #7c3aed;\n border: 2px solid #7c3aed;\n }\n\n .cb-btn-secondary:hover {\n background: #f5f3ff;\n }\n\n .cb-btn-ghost {\n background: transparent;\n color: #888;\n }\n\n .cb-btn-ghost:hover {\n color: #555;\n }\n\n .cb-step-dots {\n display: flex;\n justify-content: center;\n gap: 6px;\n margin-top: 16px;\n }\n\n .cb-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #e0e0e0;\n transition: background 0.2s ease;\n }\n\n .cb-dot.active {\n background: #7c3aed;\n }\n\n .cb-close {\n position: absolute;\n top: 12px;\n right: 12px;\n background: none;\n border: none;\n font-size: 24px;\n color: #888;\n cursor: pointer;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n }\n\n .cb-close:hover {\n background: #f0f0f0;\n color: #333;\n }\n\n .cb-modal-inner {\n position: relative;\n }\n`;\n","import type { FlowStep } from \"../core/api\";\n\nexport interface StepState {\n currentIndex: number;\n selectedReason: string | null;\n comment: string;\n totalSteps: number;\n}\n\nexport function renderStep(\n step: FlowStep,\n state: StepState,\n callbacks: {\n onNext: () => void;\n onSelectReason: (reasonId: string) => void;\n onComment: (text: string) => void;\n onAcceptOffer: (offer: Record<string, unknown>) => void;\n onDeclineOffer: () => void;\n onConfirmCancel: () => void;\n onGoBack: () => void;\n }\n): HTMLElement {\n const container = document.createElement(\"div\");\n\n switch (step.type) {\n case \"reason_survey\":\n renderReasonSurvey(container, step.config, state, callbacks);\n break;\n case \"offer\":\n renderOffer(container, step.config, callbacks);\n break;\n case \"custom_message\":\n renderCustomMessage(container, step.config, callbacks);\n break;\n case \"confirmation\":\n renderConfirmation(container, step.config, callbacks);\n break;\n }\n\n // Step dots\n if (state.totalSteps > 1) {\n const dots = document.createElement(\"div\");\n dots.className = \"cb-step-dots\";\n for (let i = 0; i < state.totalSteps; i++) {\n const dot = document.createElement(\"div\");\n dot.className = `cb-dot${i === state.currentIndex ? \" active\" : \"\"}`;\n dots.appendChild(dot);\n }\n container.appendChild(dots);\n }\n\n return container;\n}\n\nfunction renderReasonSurvey(\n container: HTMLElement,\n config: Record<string, unknown>,\n state: StepState,\n callbacks: {\n onNext: () => void;\n onSelectReason: (reasonId: string) => void;\n onComment: (text: string) => void;\n }\n) {\n const headline = document.createElement(\"h2\");\n headline.className = \"cb-headline\";\n headline.textContent = (config.headline as string) || \"Why are you cancelling?\";\n container.appendChild(headline);\n\n const reasons = (config.reasons as Array<{ id: string; label: string }>) || [];\n const reasonsDiv = document.createElement(\"div\");\n reasonsDiv.className = \"cb-reasons\";\n\n reasons.forEach((r) => {\n const btn = document.createElement(\"button\");\n btn.className = `cb-reason${state.selectedReason === r.id ? \" selected\" : \"\"}`;\n btn.textContent = r.label;\n btn.onclick = () => {\n callbacks.onSelectReason(r.id);\n // Update selection visually\n reasonsDiv.querySelectorAll(\".cb-reason\").forEach((el) => el.classList.remove(\"selected\"));\n btn.classList.add(\"selected\");\n };\n reasonsDiv.appendChild(btn);\n });\n container.appendChild(reasonsDiv);\n\n if (config.allow_comment) {\n const textarea = document.createElement(\"textarea\");\n textarea.className = \"cb-textarea\";\n textarea.placeholder = (config.comment_placeholder as string) || \"Tell us more...\";\n textarea.value = state.comment;\n textarea.oninput = () => callbacks.onComment(textarea.value);\n container.appendChild(textarea);\n }\n\n const nextBtn = document.createElement(\"button\");\n nextBtn.className = \"cb-btn cb-btn-primary\";\n nextBtn.textContent = \"Continue\";\n nextBtn.onclick = callbacks.onNext;\n container.appendChild(nextBtn);\n}\n\nfunction renderOffer(\n container: HTMLElement,\n config: Record<string, unknown>,\n callbacks: {\n onAcceptOffer: (offer: Record<string, unknown>) => void;\n onDeclineOffer: () => void;\n }\n) {\n const headline = document.createElement(\"h2\");\n headline.className = \"cb-headline\";\n headline.textContent = (config.headline as string) || \"Special offer for you\";\n container.appendChild(headline);\n\n const body = document.createElement(\"p\");\n body.className = \"cb-body\";\n body.textContent = (config.body as string) || \"\";\n container.appendChild(body);\n\n const acceptBtn = document.createElement(\"button\");\n acceptBtn.className = \"cb-btn cb-btn-primary\";\n acceptBtn.textContent = (config.cta_accept as string) || \"Accept Offer\";\n acceptBtn.onclick = () => callbacks.onAcceptOffer(config);\n container.appendChild(acceptBtn);\n\n const declineBtn = document.createElement(\"button\");\n declineBtn.className = \"cb-btn cb-btn-ghost\";\n declineBtn.textContent = (config.cta_decline as string) || \"No thanks\";\n declineBtn.onclick = callbacks.onDeclineOffer;\n container.appendChild(declineBtn);\n}\n\nfunction renderCustomMessage(\n container: HTMLElement,\n config: Record<string, unknown>,\n callbacks: { onNext: () => void }\n) {\n const headline = document.createElement(\"h2\");\n headline.className = \"cb-headline\";\n headline.textContent = (config.headline as string) || \"\";\n container.appendChild(headline);\n\n const body = document.createElement(\"p\");\n body.className = \"cb-body\";\n body.textContent = (config.body as string) || \"\";\n container.appendChild(body);\n\n if (config.cta_text) {\n const btn = document.createElement(\"button\");\n btn.className = \"cb-btn cb-btn-primary\";\n btn.textContent = config.cta_text as string;\n btn.onclick = callbacks.onNext;\n container.appendChild(btn);\n }\n}\n\nfunction renderConfirmation(\n container: HTMLElement,\n config: Record<string, unknown>,\n callbacks: {\n onConfirmCancel: () => void;\n onGoBack: () => void;\n }\n) {\n const headline = document.createElement(\"h2\");\n headline.className = \"cb-headline\";\n headline.textContent = (config.headline as string) || \"Are you sure?\";\n container.appendChild(headline);\n\n const body = document.createElement(\"p\");\n body.className = \"cb-body\";\n body.textContent = (config.body as string) || \"\";\n container.appendChild(body);\n\n const goBackBtn = document.createElement(\"button\");\n goBackBtn.className = \"cb-btn cb-btn-primary\";\n goBackBtn.textContent = (config.go_back_text as string) || \"Keep my subscription\";\n goBackBtn.onclick = callbacks.onGoBack;\n container.appendChild(goBackBtn);\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.className = \"cb-btn cb-btn-danger\";\n cancelBtn.textContent = (config.confirm_cancel_text as string) || \"Yes, cancel\";\n cancelBtn.onclick = callbacks.onConfirmCancel;\n container.appendChild(cancelBtn);\n}\n","import type { ApiClient, FlowStep, FlowResponse } from \"../core/api\";\nimport { MODAL_STYLES } from \"./styles\";\nimport { renderStep, type StepState } from \"./steps\";\n\nexport interface CancelFlowOptions {\n stripeCustomerId: string;\n stripeSubscriptionId: string;\n stripePriceId?: string;\n onComplete?: (result: CancelFlowResult) => void;\n onDismiss?: () => void;\n}\n\nexport interface CancelFlowResult {\n action: \"saved\" | \"cancelled\" | \"dismissed\";\n reason?: string;\n comment?: string;\n offerAccepted?: Record<string, unknown>;\n}\n\nexport class CancelFlowModal {\n private shadowHost: HTMLElement | null = null;\n private shadowRoot: ShadowRoot | null = null;\n private state: StepState;\n private steps: FlowStep[] = [];\n private sessionId = \"\";\n private destroyed = false;\n\n constructor(\n private api: ApiClient,\n private options: CancelFlowOptions\n ) {\n this.state = {\n currentIndex: 0,\n selectedReason: null,\n comment: \"\",\n totalSteps: 0,\n };\n }\n\n async open(): Promise<void> {\n // Fetch flow config\n let flow: FlowResponse;\n try {\n flow = await this.api.fetchCancelFlow(\n this.options.stripeCustomerId,\n this.options.stripeSubscriptionId,\n this.options.stripePriceId\n );\n } catch (err) {\n console.error(\"[ChurnBack] Failed to load cancel flow:\", err);\n throw err;\n }\n\n if (this.destroyed) return;\n\n this.sessionId = flow.sessionId;\n this.steps = flow.steps;\n this.state.totalSteps = flow.steps.length;\n\n // Create Shadow DOM host\n this.shadowHost = document.createElement(\"div\");\n this.shadowHost.id = \"churnback-modal\";\n document.body.appendChild(this.shadowHost);\n this.shadowRoot = this.shadowHost.attachShadow({ mode: \"closed\" });\n\n // Inject styles\n const style = document.createElement(\"style\");\n style.textContent = MODAL_STYLES;\n this.shadowRoot.appendChild(style);\n\n this.renderCurrentStep();\n }\n\n private renderCurrentStep(): void {\n if (!this.shadowRoot || this.destroyed) return;\n\n // Remove old content (keep style)\n const existing = this.shadowRoot.querySelector(\".cb-overlay\");\n if (existing) existing.remove();\n\n const step = this.steps[this.state.currentIndex];\n if (!step) return;\n\n const overlay = document.createElement(\"div\");\n overlay.className = \"cb-overlay\";\n overlay.onclick = (e) => {\n if (e.target === overlay) this.dismiss();\n };\n\n const modal = document.createElement(\"div\");\n modal.className = \"cb-modal\";\n\n const inner = document.createElement(\"div\");\n inner.className = \"cb-modal-inner\";\n\n // Close button\n const closeBtn = document.createElement(\"button\");\n closeBtn.className = \"cb-close\";\n closeBtn.innerHTML = \"&times;\";\n closeBtn.onclick = () => this.dismiss();\n inner.appendChild(closeBtn);\n\n const stepContent = renderStep(step, this.state, {\n onNext: () => this.nextStep(),\n onSelectReason: (id) => {\n this.state.selectedReason = id;\n },\n onComment: (text) => {\n this.state.comment = text;\n },\n onAcceptOffer: (offer) => this.acceptOffer(offer),\n onDeclineOffer: () => this.nextStep(),\n onConfirmCancel: () => this.confirmCancel(),\n onGoBack: () => this.dismiss(),\n });\n\n inner.appendChild(stepContent);\n modal.appendChild(inner);\n overlay.appendChild(modal);\n this.shadowRoot.appendChild(overlay);\n }\n\n private nextStep(): void {\n if (this.state.currentIndex < this.steps.length - 1) {\n this.state.currentIndex++;\n this.renderCurrentStep();\n }\n }\n\n private async acceptOffer(offer: Record<string, unknown>): Promise<void> {\n try {\n await this.api.submitResult({\n sessionId: this.sessionId,\n action: \"offer_accepted\",\n reason: this.state.selectedReason || undefined,\n comment: this.state.comment || undefined,\n acceptedOffer: offer,\n });\n } catch (err) {\n console.error(\"[ChurnBack] Failed to submit offer acceptance:\", err);\n }\n\n this.close();\n this.options.onComplete?.({\n action: \"saved\",\n reason: this.state.selectedReason || undefined,\n comment: this.state.comment || undefined,\n offerAccepted: offer,\n });\n }\n\n private async confirmCancel(): Promise<void> {\n try {\n await this.api.submitResult({\n sessionId: this.sessionId,\n action: \"cancelled\",\n reason: this.state.selectedReason || undefined,\n comment: this.state.comment || undefined,\n });\n } catch (err) {\n console.error(\"[ChurnBack] Failed to submit cancellation:\", err);\n }\n\n this.close();\n this.options.onComplete?.({\n action: \"cancelled\",\n reason: this.state.selectedReason || undefined,\n comment: this.state.comment || undefined,\n });\n }\n\n private async dismiss(): Promise<void> {\n try {\n await this.api.submitResult({\n sessionId: this.sessionId,\n action: \"abandoned\",\n });\n } catch {\n // Silent fail on dismiss\n }\n\n this.close();\n this.options.onDismiss?.();\n this.options.onComplete?.({ action: \"dismissed\" });\n }\n\n private close(): void {\n if (this.shadowHost && this.shadowHost.parentNode) {\n this.shadowHost.parentNode.removeChild(this.shadowHost);\n }\n this.shadowHost = null;\n this.shadowRoot = null;\n }\n\n destroy(): void {\n this.destroyed = true;\n this.close();\n }\n}\n","export const BANNER_STYLES = `\n .cb-dunning-banner {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 10px;\n padding: 16px 20px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n flex-wrap: wrap;\n }\n\n .cb-dunning-content {\n flex: 1;\n min-width: 200px;\n }\n\n .cb-dunning-headline {\n font-size: 15px;\n font-weight: 600;\n color: #991b1b;\n margin-bottom: 4px;\n }\n\n .cb-dunning-body {\n font-size: 13px;\n color: #b91c1c;\n line-height: 1.4;\n }\n\n .cb-dunning-cta {\n padding: 8px 16px;\n background: #ef4444;\n color: white;\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n white-space: nowrap;\n transition: background 0.15s ease;\n text-decoration: none;\n display: inline-block;\n }\n\n .cb-dunning-cta:hover {\n background: #dc2626;\n }\n\n .cb-dunning-hidden {\n display: none;\n }\n`;\n","import type { ApiClient, DunningResponse } from \"../core/api\";\nimport { BANNER_STYLES } from \"./styles\";\n\nexport interface DunningBannerOptions {\n stripeCustomerId: string;\n targetElement: string | HTMLElement;\n}\n\nexport class DunningBanner {\n private shadowHost: HTMLElement | null = null;\n private destroyed = false;\n\n constructor(\n private api: ApiClient,\n private options: DunningBannerOptions\n ) {}\n\n async mount(): Promise<void> {\n let dunning: DunningResponse;\n try {\n dunning = await this.api.checkDunning(this.options.stripeCustomerId);\n } catch {\n return; // Silent fail\n }\n\n if (this.destroyed || !dunning.hasFailedPayment) return;\n\n const target =\n typeof this.options.targetElement === \"string\"\n ? document.querySelector(this.options.targetElement)\n : this.options.targetElement;\n\n if (!target) {\n console.warn(\"[ChurnBack] Dunning banner target element not found\");\n return;\n }\n\n this.shadowHost = document.createElement(\"div\");\n const shadow = this.shadowHost.attachShadow({ mode: \"closed\" });\n\n const style = document.createElement(\"style\");\n style.textContent = BANNER_STYLES;\n shadow.appendChild(style);\n\n const banner = document.createElement(\"div\");\n banner.className = \"cb-dunning-banner\";\n\n const content = document.createElement(\"div\");\n content.className = \"cb-dunning-content\";\n\n const headline = document.createElement(\"div\");\n headline.className = \"cb-dunning-headline\";\n headline.textContent = dunning.bannerConfig?.headline || \"Payment failed\";\n\n const body = document.createElement(\"div\");\n body.className = \"cb-dunning-body\";\n body.textContent =\n dunning.bannerConfig?.body ||\n `We were unable to process your payment${dunning.amountDueCents ? ` of $${(dunning.amountDueCents / 100).toFixed(2)}` : \"\"}. Please update your payment method to avoid service interruption.`;\n\n content.appendChild(headline);\n content.appendChild(body);\n banner.appendChild(content);\n\n if (dunning.updatePaymentUrl) {\n const cta = document.createElement(\"a\");\n cta.className = \"cb-dunning-cta\";\n cta.href = dunning.updatePaymentUrl;\n cta.target = \"_blank\";\n cta.rel = \"noopener noreferrer\";\n cta.textContent = dunning.bannerConfig?.ctaText || \"Update Payment\";\n banner.appendChild(cta);\n }\n\n shadow.appendChild(banner);\n target.appendChild(this.shadowHost);\n }\n\n destroy(): void {\n this.destroyed = true;\n if (this.shadowHost && this.shadowHost.parentNode) {\n this.shadowHost.parentNode.removeChild(this.shadowHost);\n }\n this.shadowHost = null;\n }\n}\n","import { resolveConfig, type ChurnBackConfig } from \"./core/config\";\nimport { ApiClient, type DunningResponse } from \"./core/api\";\nimport { CancelFlowModal, type CancelFlowOptions, type CancelFlowResult } from \"./cancel-flow/modal\";\nimport { DunningBanner, type DunningBannerOptions } from \"./dunning/banner\";\n\nexport type { ChurnBackConfig, CancelFlowOptions, CancelFlowResult, DunningResponse };\n\nexport class ChurnBackClient {\n private api: ApiClient;\n private activeModal: CancelFlowModal | null = null;\n private activeBanners: DunningBanner[] = [];\n\n constructor(config: ChurnBackConfig) {\n if (!config.apiKey) {\n throw new Error(\"[ChurnBack] apiKey is required\");\n }\n const resolved = resolveConfig(config);\n this.api = new ApiClient(resolved);\n }\n\n async triggerCancelFlow(options: CancelFlowOptions): Promise<void> {\n this.activeModal?.destroy();\n\n const modal = new CancelFlowModal(this.api, options);\n this.activeModal = modal;\n await modal.open();\n }\n\n async checkDunning(options: { stripeCustomerId: string }): Promise<DunningResponse> {\n return this.api.checkDunning(options.stripeCustomerId);\n }\n\n mountDunningBanner(options: DunningBannerOptions): void {\n const banner = new DunningBanner(this.api, options);\n this.activeBanners.push(banner);\n banner.mount();\n }\n\n destroy(): void {\n this.activeModal?.destroy();\n this.activeModal = null;\n this.activeBanners.forEach((b) => b.destroy());\n this.activeBanners = [];\n }\n}\n\nexport default ChurnBackClient;\n"],"mappings":"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","names":["resolveConfig","config","ApiClient","config","customerId","subscriptionId","priceId","params","res","body","payload","MODAL_STYLES","renderStep","step","state","callbacks","container","renderReasonSurvey","renderOffer","renderCustomMessage","renderConfirmation","dots","i","dot","config","headline","reasons","reasonsDiv","btn","el","textarea","nextBtn","body","acceptBtn","declineBtn","goBackBtn","cancelBtn","CancelFlowModal","api","options","flow","err","style","MODAL_STYLES","existing","step","overlay","e","modal","inner","closeBtn","stepContent","renderStep","id","text","offer","BANNER_STYLES","DunningBanner","api","options","dunning","target","shadow","style","BANNER_STYLES","banner","content","headline","body","cta","ChurnBackClient","config","resolved","resolveConfig","ApiClient","options","modal","CancelFlowModal","banner","DunningBanner","b","index_default"]}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@churnback/sdk",
3
+ "version": "0.1.0",
4
+ "description": "ChurnBack JavaScript SDK - Reduce churn with intelligent cancel flows",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/JTVOLPS/ChurnBack.git",
9
+ "directory": "packages/sdk"
10
+ },
11
+ "homepage": "https://churnback.ai",
12
+ "bugs": {
13
+ "url": "https://github.com/JTVOLPS/ChurnBack/issues"
14
+ },
15
+ "keywords": [
16
+ "churn",
17
+ "retention",
18
+ "cancel-flow",
19
+ "dunning",
20
+ "stripe",
21
+ "saas",
22
+ "subscription"
23
+ ],
24
+ "main": "dist/index.js",
25
+ "module": "dist/index.mjs",
26
+ "types": "dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.mjs",
31
+ "require": "./dist/index.js"
32
+ }
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "LICENSE",
37
+ "README.md"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "dev": "tsup --watch",
42
+ "lint": "echo 'no lint configured'",
43
+ "test": "vitest run",
44
+ "prepublishOnly": "npm run build"
45
+ },
46
+ "devDependencies": {
47
+ "jsdom": "^28.1.0",
48
+ "tsup": "^8.4.0",
49
+ "typescript": "^5.9.0",
50
+ "vitest": "^4.0.18"
51
+ }
52
+ }