@churnkey/react 0.6.1 → 0.6.3
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/dist/{chunk-YKDJMCSW.cjs → chunk-224XOEYJ.cjs} +6 -6
- package/dist/{chunk-YKDJMCSW.cjs.map → chunk-224XOEYJ.cjs.map} +1 -1
- package/dist/{chunk-G57YLYM5.js → chunk-EYIGZLVT.js} +3 -74
- package/dist/chunk-EYIGZLVT.js.map +1 -0
- package/dist/{chunk-4FGFYJPW.js → chunk-J6BBPG6T.cjs} +88 -3
- package/dist/chunk-J6BBPG6T.cjs.map +1 -0
- package/dist/{chunk-IXGAI4LH.cjs → chunk-KS2T4QBH.js} +77 -7
- package/dist/chunk-KS2T4QBH.js.map +1 -0
- package/dist/{chunk-BDBZ5OS3.cjs → chunk-WVSNF3TN.cjs} +2 -78
- package/dist/chunk-WVSNF3TN.cjs.map +1 -0
- package/dist/{chunk-DJ5AAFK2.js → chunk-ZIH7TTIZ.js} +3 -3
- package/dist/{chunk-DJ5AAFK2.js.map → chunk-ZIH7TTIZ.js.map} +1 -1
- package/dist/core.cjs +26 -26
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +2 -2
- package/dist/headless.cjs +3 -3
- package/dist/headless.d.cts +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +2 -2
- package/dist/index.cjs +120 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +9 -15
- package/dist/index.js.map +1 -1
- package/dist/{step-graph-DX8yCqq1.d.ts → step-graph-BpoAhd0d.d.cts} +6 -0
- package/dist/{step-graph-DX8yCqq1.d.cts → step-graph-BpoAhd0d.d.ts} +6 -0
- package/package.json +1 -1
- package/dist/chunk-4FGFYJPW.js.map +0 -1
- package/dist/chunk-BDBZ5OS3.cjs.map +0 -1
- package/dist/chunk-G57YLYM5.js.map +0 -1
- package/dist/chunk-IXGAI4LH.cjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkJ6BBPG6T_cjs = require('./chunk-J6BBPG6T.cjs');
|
|
4
4
|
var react = require('react');
|
|
5
5
|
|
|
6
6
|
function useCancelFlowMachine(config) {
|
|
@@ -25,7 +25,7 @@ function useCancelFlowMachine(config) {
|
|
|
25
25
|
onClose: () => cb.current.onClose?.(),
|
|
26
26
|
onStepChange: (step, prevStep) => cb.current.onStepChange?.(step, prevStep)
|
|
27
27
|
};
|
|
28
|
-
return new
|
|
28
|
+
return new chunkJ6BBPG6T_cjs.CancelFlowMachine({ ...config, ...dispatch });
|
|
29
29
|
});
|
|
30
30
|
const [state, setState] = react.useState(() => machine.getSnapshot());
|
|
31
31
|
const [isLoading, setIsLoading] = react.useState(!!config.session);
|
|
@@ -39,8 +39,8 @@ function useCancelFlowMachine(config) {
|
|
|
39
39
|
setLoadError(null);
|
|
40
40
|
setIsLoading(true);
|
|
41
41
|
let cancelled = false;
|
|
42
|
-
const creds =
|
|
43
|
-
const api = new
|
|
42
|
+
const creds = chunkJ6BBPG6T_cjs.decodeSessionToken(config.session);
|
|
43
|
+
const api = new chunkJ6BBPG6T_cjs.ChurnkeyApi(creds, config.apiBaseUrl);
|
|
44
44
|
api.fetchConfig(callbacksRef.current.customerAttributes).then((sdkConfig) => {
|
|
45
45
|
if (cancelled) return;
|
|
46
46
|
machine.initializeFromConfig(sdkConfig, api, creds);
|
|
@@ -88,5 +88,5 @@ function useCancelFlow(config) {
|
|
|
88
88
|
|
|
89
89
|
exports.useCancelFlow = useCancelFlow;
|
|
90
90
|
exports.useCancelFlowMachine = useCancelFlowMachine;
|
|
91
|
-
//# sourceMappingURL=chunk-
|
|
92
|
-
//# sourceMappingURL=chunk-
|
|
91
|
+
//# sourceMappingURL=chunk-224XOEYJ.cjs.map
|
|
92
|
+
//# sourceMappingURL=chunk-224XOEYJ.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/headless/use-cancel-flow-machine.ts","../src/headless/use-cancel-flow.ts"],"names":["useRef","useState","CancelFlowMachine","useEffect","useCallback","decodeSessionToken","ChurnkeyApi"],"mappings":"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","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/headless/use-cancel-flow-machine.ts","../src/headless/use-cancel-flow.ts"],"names":["useRef","useState","CancelFlowMachine","useEffect","useCallback","decodeSessionToken","ChurnkeyApi"],"mappings":"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","file":"chunk-224XOEYJ.cjs","sourcesContent":["// Internal — shared by `useCancelFlow` (headless) and the `CancelFlow`\n// component. Lives under headless/ since it's the headless layer of the\n// SDK; the component imports it because there's no separate public/private\n// split worth maintaining for one shared file.\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { ChurnkeyApi } from '../core/api'\nimport { CancelFlowMachine } from '../core/machine'\nimport { decodeSessionToken } from '../core/token'\nimport type { FlowCallbacks, FlowConfig, FlowState } from '../core/types'\n\nexport interface CancelFlowMachineHandle {\n machine: CancelFlowMachine\n state: FlowState\n isLoading: boolean\n loadError: Error | null\n /** Re-fetch the flow config (token mode only). No-op without a session. */\n retry: () => void\n}\n\n/**\n * Wires a CancelFlowMachine to React lifecycle. Used internally by both the\n * `CancelFlow` component and the `useCancelFlow` hook — not part of the\n * public API.\n *\n * Callbacks reach the machine via thunks that dereference a ref updated each\n * render. This buys two things: the consumer's latest closure always runs,\n * and the fetch effect's dep list stays stable so inline-arrow handlers\n * don't trigger a re-fetch and reset the flow to step 1.\n */\nexport function useCancelFlowMachine(config: FlowConfig): CancelFlowMachineHandle {\n // FlowConfig extends FlowCallbacks, so storing the whole config gives us\n // access to every callback by name without a separate copy.\n const callbacksRef = useRef(config)\n callbacksRef.current = config\n\n const [machine] = useState(() => {\n const cb = callbacksRef\n const dispatch: FlowCallbacks = {\n handleDiscount: (o, c) => cb.current.handleDiscount?.(o, c),\n handlePause: (o, c) => cb.current.handlePause?.(o, c),\n handlePlanChange: (o, c) => cb.current.handlePlanChange?.(o, c),\n handleTrialExtension: (o, c) => cb.current.handleTrialExtension?.(o, c),\n handleRebate: (o, c) => cb.current.handleRebate?.(o, c),\n handleCancel: (c) => cb.current.handleCancel?.(c),\n onAccept: (o, c) => cb.current.onAccept?.(o, c),\n onDiscount: (o, c) => cb.current.onDiscount?.(o, c),\n onPause: (o, c) => cb.current.onPause?.(o, c),\n onPlanChange: (o, c) => cb.current.onPlanChange?.(o, c),\n onTrialExtension: (o, c) => cb.current.onTrialExtension?.(o, c),\n onRebate: (o, c) => cb.current.onRebate?.(o, c),\n onCancel: (c) => cb.current.onCancel?.(c),\n onClose: () => cb.current.onClose?.(),\n onStepChange: (step, prevStep) => cb.current.onStepChange?.(step, prevStep),\n }\n return new CancelFlowMachine({ ...config, ...dispatch })\n })\n\n const [state, setState] = useState<FlowState>(() => machine.getSnapshot())\n const [isLoading, setIsLoading] = useState(!!config.session)\n const [loadError, setLoadError] = useState<Error | null>(null)\n\n useEffect(() => {\n setState(machine.getSnapshot())\n return machine.subscribe(() => setState(machine.getSnapshot()))\n }, [machine])\n\n const loadConfig = useCallback(() => {\n if (!config.session) return\n setLoadError(null)\n setIsLoading(true)\n let cancelled = false\n const creds = decodeSessionToken(config.session)\n const api = new ChurnkeyApi(creds, config.apiBaseUrl)\n api\n // Read through the ref, not the closure: an inline `customerAttributes`\n // object literal would otherwise join the dep list and re-fetch (and\n // reset the flow) on every render.\n .fetchConfig(callbacksRef.current.customerAttributes)\n .then((sdkConfig) => {\n if (cancelled) return\n machine.initializeFromConfig(sdkConfig, api, creds)\n setIsLoading(false)\n })\n .catch((err) => {\n if (cancelled) return\n setLoadError(err instanceof Error ? err : new Error(String(err)))\n setIsLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [config.session, config.apiBaseUrl, machine])\n\n useEffect(() => {\n if (!config.session) return\n return loadConfig()\n }, [config.session, loadConfig])\n\n return { machine, state, isLoading, loadError, retry: loadConfig }\n}\n","import type { FlowConfig } from '../core/types'\nimport { useCancelFlowMachine } from './use-cancel-flow-machine'\n\nexport function useCancelFlow(config: FlowConfig) {\n const { machine, state, isLoading, loadError, retry } = useCancelFlowMachine(config)\n\n return {\n ...state,\n isLoading,\n loadError,\n retry,\n reasons: machine.reasons,\n currentStep: machine.currentStep,\n currentOffer: machine.currentOffer,\n stepIndex: machine.stepIndex,\n totalSteps: machine.totalSteps,\n selectReason: machine.selectReason,\n setFollowupResponse: machine.setFollowupResponse,\n setFeedback: machine.setFeedback,\n accept: machine.accept,\n decline: machine.decline,\n cancel: machine.cancel,\n next: machine.next,\n back: machine.back,\n close: machine.close,\n }\n}\n"]}
|
|
@@ -71,77 +71,6 @@ function discountPhrase(opts) {
|
|
|
71
71
|
return tail ? `${amount} ${tail}` : amount;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"discount",
|
|
78
|
-
"pause",
|
|
79
|
-
"trial_extension",
|
|
80
|
-
"plan_change",
|
|
81
|
-
"contact",
|
|
82
|
-
"redirect",
|
|
83
|
-
"rebate"
|
|
84
|
-
];
|
|
85
|
-
function cn(...classes) {
|
|
86
|
-
return classes.filter(Boolean).join(" ");
|
|
87
|
-
}
|
|
88
|
-
var VAR_MAP = {
|
|
89
|
-
// Surfaces
|
|
90
|
-
"--ck-color-bg": "colorBackground",
|
|
91
|
-
"--ck-color-surface": "colorSurface",
|
|
92
|
-
"--ck-color-surface-muted": "colorSurfaceMuted",
|
|
93
|
-
// Borders
|
|
94
|
-
"--ck-color-border": "colorBorder",
|
|
95
|
-
"--ck-color-border-strong": "colorBorderStrong",
|
|
96
|
-
// Text
|
|
97
|
-
"--ck-color-text": "colorText",
|
|
98
|
-
"--ck-color-text-secondary": "colorTextSecondary",
|
|
99
|
-
"--ck-color-text-muted": "colorTextMuted",
|
|
100
|
-
// Primary
|
|
101
|
-
"--ck-color-primary": "colorPrimary",
|
|
102
|
-
"--ck-color-primary-hover": "colorPrimaryHover",
|
|
103
|
-
"--ck-color-primary-soft": "colorPrimarySoft",
|
|
104
|
-
// Semantic
|
|
105
|
-
"--ck-color-success": "colorSuccess",
|
|
106
|
-
"--ck-color-success-soft": "colorSuccessSoft",
|
|
107
|
-
"--ck-color-danger": "colorDanger",
|
|
108
|
-
"--ck-color-danger-hover": "colorDangerHover",
|
|
109
|
-
"--ck-color-danger-soft": "colorDangerSoft",
|
|
110
|
-
// Typography
|
|
111
|
-
"--ck-font-family": "fontFamily",
|
|
112
|
-
"--ck-font-mono": "fontFamilyMono",
|
|
113
|
-
"--ck-font-display": "fontFamilyDisplay",
|
|
114
|
-
"--ck-font-size": "fontSize",
|
|
115
|
-
"--ck-step-title-weight": "fontWeightDisplay",
|
|
116
|
-
"--ck-step-title-letter-spacing": "letterSpacingDisplay",
|
|
117
|
-
// Geometry
|
|
118
|
-
"--ck-border-radius": "borderRadius",
|
|
119
|
-
"--ck-radius-sm": "radiusSm",
|
|
120
|
-
"--ck-radius-md": "radiusMd",
|
|
121
|
-
"--ck-radius-lg": "radiusLg",
|
|
122
|
-
"--ck-radius-xl": "radiusXl",
|
|
123
|
-
// Elevation
|
|
124
|
-
"--ck-shadow-modal": "shadowModal",
|
|
125
|
-
"--ck-shadow-card": "shadowCard",
|
|
126
|
-
// Overlay
|
|
127
|
-
"--ck-overlay-color": "overlayColor"
|
|
128
|
-
};
|
|
129
|
-
function appearanceToStyle(appearance) {
|
|
130
|
-
const variables = appearance?.variables;
|
|
131
|
-
if (!variables) return void 0;
|
|
132
|
-
const style = {};
|
|
133
|
-
for (const [cssProp, varKey] of Object.entries(VAR_MAP)) {
|
|
134
|
-
const value = variables[varKey];
|
|
135
|
-
if (value) style[cssProp] = value;
|
|
136
|
-
}
|
|
137
|
-
return Object.keys(style).length > 0 ? style : void 0;
|
|
138
|
-
}
|
|
139
|
-
var defaultTitles = {
|
|
140
|
-
survey: "Why are you cancelling?",
|
|
141
|
-
feedback: "Any other feedback?",
|
|
142
|
-
confirm: "Confirm cancellation"
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
export { BUILT_IN_OFFER_TYPES, BUILT_IN_STEP_TYPES, appearanceToStyle, calculateDiscountedPrice, cn, defaultTitles, discountPhrase, formatMonthDay, formatMonthDayLong, formatPeriodEnd, formatPrice, formatPriceFromMinor };
|
|
146
|
-
//# sourceMappingURL=chunk-G57YLYM5.js.map
|
|
147
|
-
//# sourceMappingURL=chunk-G57YLYM5.js.map
|
|
74
|
+
export { calculateDiscountedPrice, discountPhrase, formatMonthDay, formatMonthDayLong, formatPeriodEnd, formatPrice, formatPriceFromMinor };
|
|
75
|
+
//# sourceMappingURL=chunk-EYIGZLVT.js.map
|
|
76
|
+
//# sourceMappingURL=chunk-EYIGZLVT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/format.ts"],"names":[],"mappings":"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","file":"chunk-EYIGZLVT.js","sourcesContent":["import type { DirectSubscription } from './types'\n\n// Currencies whose smallest unit equals one major unit (no fractional part).\n// Stripe and most billing providers store these without an implicit /100.\nconst ZERO_DECIMAL_CURRENCIES: ReadonlySet<string> = new Set([\n 'BIF',\n 'CLP',\n 'DJF',\n 'GNF',\n 'JPY',\n 'KMF',\n 'KRW',\n 'MGA',\n 'PYG',\n 'RWF',\n 'UGX',\n 'VND',\n 'VUV',\n 'XAF',\n 'XOF',\n 'XPF',\n])\n\n// Middle-Eastern currencies that use three fractional digits (1000 divisor).\n// Without this bucket, JOD/KWD amounts would be off by 10x in display.\nconst THREE_DECIMAL_CURRENCIES: ReadonlySet<string> = new Set(['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND'])\n\nexport function isZeroDecimalCurrency(currency: string): boolean {\n return ZERO_DECIMAL_CURRENCIES.has(currency.toUpperCase())\n}\n\nexport function isThreeDecimalCurrency(currency: string): boolean {\n return THREE_DECIMAL_CURRENCIES.has(currency.toUpperCase())\n}\n\n/**\n * Smallest-unit divisor for a currency. 1 for zero-decimal (JPY), 1000 for\n * three-decimal (KWD), 100 for everything else. Used to convert provider\n * amounts (which are always in the smallest unit) into the major unit for\n * display.\n */\nexport function getCurrencyDivisor(currency = 'USD'): number {\n if (isZeroDecimalCurrency(currency)) return 1\n if (isThreeDecimalCurrency(currency)) return 1000\n return 100\n}\n\n/**\n * Converts a Direct.Price.amount.value (smallest currency unit) into the\n * major unit used for display.\n */\nexport function convertFromMinorUnits(value: number, currency = 'USD'): number {\n return value / getCurrencyDivisor(currency)\n}\n\n/**\n * Format an amount already in the major unit. Uses `narrowSymbol` so output\n * reads \"$29\" rather than \"US$29\", and trims trailing zero fractions so\n * whole amounts render compactly.\n */\nexport function formatPrice(amount: number, currency = 'USD', locale?: string): string {\n try {\n const formatted = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n currencyDisplay: 'narrowSymbol',\n }).format(amount)\n return formatted.replace(/[.,]00$/, '')\n } catch {\n return `${currency} ${amount.toFixed(2)}`\n }\n}\n\n/** Convenience: format a Direct-shape minor-unit amount in one call. */\nexport function formatPriceFromMinor(value: number, currency = 'USD', locale?: string): string {\n return formatPrice(convertFromMinorUnits(value, currency), currency, locale)\n}\n\nexport function calculateDiscountedPrice(originalPrice: number, percentOff: number): number {\n return originalPrice * (1 - percentOff / 100)\n}\n\n// ─── Dates ────────────────────────────────────────────────────────────────\n\n/** \"Apr 30, 2026\" — used for resume dates and other full-date contexts. */\nexport function formatShortDate(date: Date, locale?: string): string {\n return date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\n/** \"Apr 30\" — used when the year is implied by context. */\nexport function formatMonthDay(date: Date, locale?: string): string {\n return date.toLocaleDateString(locale, { month: 'short', day: 'numeric' })\n}\n\n/** \"April 30\" — long month form for prominent date displays. */\nexport function formatMonthDayLong(date: Date, locale?: string): string {\n return date.toLocaleDateString(locale, { month: 'long', day: 'numeric' })\n}\n\n/**\n * Long-form access period end (\"June 14, 2026\") for the first subscription's\n * current period. Returns null for canceled subscriptions, missing periods,\n * and unparseable dates so Confirm can drop the \"access continues until\"\n * notice cleanly instead of rendering \"Invalid Date\".\n */\nexport function formatPeriodEnd(\n subscriptions: DirectSubscription[] | null | undefined,\n locale?: string,\n): string | null {\n const status = subscriptions?.[0]?.status\n if (!status || !('currentPeriod' in status) || !status.currentPeriod?.end) return null\n const end = status.currentPeriod.end\n const d = end instanceof Date ? end : new Date(end)\n if (Number.isNaN(d.getTime())) return null\n return d.toLocaleDateString(locale, { month: 'long', day: 'numeric', year: 'numeric' })\n}\n\n// ─── Discount phrasing ─────────────────────────────────────────────────────\n\n/**\n * Renders the discount as a single human-readable sentence:\n * \"25% off for 3 months\" / \"$5 off your next renewal\" / \"20% off for life\"\n *\n * Mirrors the embed's couponToString helper so SDK and embed use the same\n * phrasing for the same offer shape.\n */\nexport function discountPhrase(opts: {\n percentOff?: number\n /** Smallest currency unit (cents for USD). */\n amountOff?: number\n currency?: string\n duration?: 'once' | 'repeating' | 'forever'\n durationInMonths?: number\n}): string {\n const { percentOff, amountOff, currency, duration, durationInMonths } = opts\n const amount =\n percentOff != null\n ? `${percentOff}% off`\n : amountOff != null\n ? `${formatPriceFromMinor(amountOff, currency)} off`\n : 'discount'\n const tail =\n duration === 'once'\n ? 'your next renewal'\n : duration === 'forever'\n ? 'for life'\n : durationInMonths\n ? `for ${durationInMonths} ${durationInMonths === 1 ? 'month' : 'months'}`\n : ''\n return tail ? `${amount} ${tail}` : amount\n}\n"]}
|
|
@@ -1,3 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/utils.ts
|
|
4
|
+
var BUILT_IN_STEP_TYPES = ["survey", "offer", "feedback", "confirm", "success"];
|
|
5
|
+
var BUILT_IN_OFFER_TYPES = [
|
|
6
|
+
"discount",
|
|
7
|
+
"pause",
|
|
8
|
+
"trial_extension",
|
|
9
|
+
"plan_change",
|
|
10
|
+
"contact",
|
|
11
|
+
"redirect",
|
|
12
|
+
"rebate"
|
|
13
|
+
];
|
|
14
|
+
function cn(...classes) {
|
|
15
|
+
return classes.filter(Boolean).join(" ");
|
|
16
|
+
}
|
|
17
|
+
var VAR_MAP = {
|
|
18
|
+
// Surfaces
|
|
19
|
+
"--ck-color-bg": "colorBackground",
|
|
20
|
+
"--ck-color-surface": "colorSurface",
|
|
21
|
+
"--ck-color-surface-muted": "colorSurfaceMuted",
|
|
22
|
+
// Borders
|
|
23
|
+
"--ck-color-border": "colorBorder",
|
|
24
|
+
"--ck-color-border-strong": "colorBorderStrong",
|
|
25
|
+
// Text
|
|
26
|
+
"--ck-color-text": "colorText",
|
|
27
|
+
"--ck-color-text-secondary": "colorTextSecondary",
|
|
28
|
+
"--ck-color-text-muted": "colorTextMuted",
|
|
29
|
+
// Primary
|
|
30
|
+
"--ck-color-primary": "colorPrimary",
|
|
31
|
+
"--ck-color-primary-hover": "colorPrimaryHover",
|
|
32
|
+
"--ck-color-primary-soft": "colorPrimarySoft",
|
|
33
|
+
// Semantic
|
|
34
|
+
"--ck-color-success": "colorSuccess",
|
|
35
|
+
"--ck-color-success-soft": "colorSuccessSoft",
|
|
36
|
+
"--ck-color-danger": "colorDanger",
|
|
37
|
+
"--ck-color-danger-hover": "colorDangerHover",
|
|
38
|
+
"--ck-color-danger-soft": "colorDangerSoft",
|
|
39
|
+
// Typography
|
|
40
|
+
"--ck-font-family": "fontFamily",
|
|
41
|
+
"--ck-font-mono": "fontFamilyMono",
|
|
42
|
+
"--ck-font-display": "fontFamilyDisplay",
|
|
43
|
+
"--ck-font-size": "fontSize",
|
|
44
|
+
"--ck-step-title-weight": "fontWeightDisplay",
|
|
45
|
+
"--ck-step-title-letter-spacing": "letterSpacingDisplay",
|
|
46
|
+
// Geometry
|
|
47
|
+
"--ck-border-radius": "borderRadius",
|
|
48
|
+
"--ck-radius-sm": "radiusSm",
|
|
49
|
+
"--ck-radius-md": "radiusMd",
|
|
50
|
+
"--ck-radius-lg": "radiusLg",
|
|
51
|
+
"--ck-radius-xl": "radiusXl",
|
|
52
|
+
// Elevation
|
|
53
|
+
"--ck-shadow-modal": "shadowModal",
|
|
54
|
+
"--ck-shadow-card": "shadowCard",
|
|
55
|
+
// Overlay
|
|
56
|
+
"--ck-overlay-color": "overlayColor"
|
|
57
|
+
};
|
|
58
|
+
function appearanceToStyle(appearance) {
|
|
59
|
+
const variables = appearance?.variables;
|
|
60
|
+
if (!variables) return void 0;
|
|
61
|
+
const style = {};
|
|
62
|
+
for (const [cssProp, varKey] of Object.entries(VAR_MAP)) {
|
|
63
|
+
const value = variables[varKey];
|
|
64
|
+
if (value) style[cssProp] = value;
|
|
65
|
+
}
|
|
66
|
+
return Object.keys(style).length > 0 ? style : void 0;
|
|
67
|
+
}
|
|
68
|
+
var defaultTitles = {
|
|
69
|
+
survey: "Why are you cancelling?",
|
|
70
|
+
feedback: "Any other feedback?",
|
|
71
|
+
confirm: "Confirm cancellation"
|
|
72
|
+
};
|
|
73
|
+
|
|
1
74
|
// src/core/api.ts
|
|
2
75
|
var DEFAULT_BASE_URL = "https://api.churnkey.co/v1";
|
|
3
76
|
function toApiMode(mode) {
|
|
@@ -394,6 +467,10 @@ function transformOfferDecision(o) {
|
|
|
394
467
|
return { ...transformOfferConfig(o), copy: o.copy, decisionId: o.decisionId };
|
|
395
468
|
}
|
|
396
469
|
function transformOfferConfig(o) {
|
|
470
|
+
if (!BUILT_IN_OFFER_TYPES.includes(o.type)) {
|
|
471
|
+
const custom = o;
|
|
472
|
+
return custom.data !== void 0 ? { type: custom.type, data: custom.data } : { type: custom.type };
|
|
473
|
+
}
|
|
397
474
|
switch (o.type) {
|
|
398
475
|
case "discount": {
|
|
399
476
|
const d = o;
|
|
@@ -1125,6 +1202,14 @@ function decodeSessionToken(token) {
|
|
|
1125
1202
|
};
|
|
1126
1203
|
}
|
|
1127
1204
|
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1205
|
+
exports.AnalyticsClient = AnalyticsClient;
|
|
1206
|
+
exports.BUILT_IN_OFFER_TYPES = BUILT_IN_OFFER_TYPES;
|
|
1207
|
+
exports.BUILT_IN_STEP_TYPES = BUILT_IN_STEP_TYPES;
|
|
1208
|
+
exports.CancelFlowMachine = CancelFlowMachine;
|
|
1209
|
+
exports.ChurnkeyApi = ChurnkeyApi;
|
|
1210
|
+
exports.appearanceToStyle = appearanceToStyle;
|
|
1211
|
+
exports.cn = cn;
|
|
1212
|
+
exports.decodeSessionToken = decodeSessionToken;
|
|
1213
|
+
exports.defaultTitles = defaultTitles;
|
|
1214
|
+
//# sourceMappingURL=chunk-J6BBPG6T.cjs.map
|
|
1215
|
+
//# sourceMappingURL=chunk-J6BBPG6T.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/utils.ts","../src/core/api.ts","../src/core/merge-fields.ts","../src/core/step-graph.ts","../src/core/transform.ts","../src/core/machine.ts","../src/core/types.ts","../src/core/token.ts"],"names":["defaultOfferCopy"],"mappings":"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","file":"chunk-J6BBPG6T.cjs","sourcesContent":["import type { CSSProperties } from 'react'\nimport type { Appearance, AppearanceVariables } from './types'\n\nexport const BUILT_IN_STEP_TYPES: readonly string[] = ['survey', 'offer', 'feedback', 'confirm', 'success']\nexport const BUILT_IN_OFFER_TYPES: readonly string[] = [\n 'discount',\n 'pause',\n 'trial_extension',\n 'plan_change',\n 'contact',\n 'redirect',\n 'rebate',\n]\n\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(' ')\n}\n\n// Maps the typed `appearance.variables` field names to the underlying\n// CSS custom properties. Light/dark variants live in CSS — these\n// overrides apply on top of whichever scheme is active.\nconst VAR_MAP: Record<string, keyof AppearanceVariables> = {\n // Surfaces\n '--ck-color-bg': 'colorBackground',\n '--ck-color-surface': 'colorSurface',\n '--ck-color-surface-muted': 'colorSurfaceMuted',\n\n // Borders\n '--ck-color-border': 'colorBorder',\n '--ck-color-border-strong': 'colorBorderStrong',\n\n // Text\n '--ck-color-text': 'colorText',\n '--ck-color-text-secondary': 'colorTextSecondary',\n '--ck-color-text-muted': 'colorTextMuted',\n\n // Primary\n '--ck-color-primary': 'colorPrimary',\n '--ck-color-primary-hover': 'colorPrimaryHover',\n '--ck-color-primary-soft': 'colorPrimarySoft',\n\n // Semantic\n '--ck-color-success': 'colorSuccess',\n '--ck-color-success-soft': 'colorSuccessSoft',\n '--ck-color-danger': 'colorDanger',\n '--ck-color-danger-hover': 'colorDangerHover',\n '--ck-color-danger-soft': 'colorDangerSoft',\n\n // Typography\n '--ck-font-family': 'fontFamily',\n '--ck-font-mono': 'fontFamilyMono',\n '--ck-font-display': 'fontFamilyDisplay',\n '--ck-font-size': 'fontSize',\n '--ck-step-title-weight': 'fontWeightDisplay',\n '--ck-step-title-letter-spacing': 'letterSpacingDisplay',\n\n // Geometry\n '--ck-border-radius': 'borderRadius',\n '--ck-radius-sm': 'radiusSm',\n '--ck-radius-md': 'radiusMd',\n '--ck-radius-lg': 'radiusLg',\n '--ck-radius-xl': 'radiusXl',\n\n // Elevation\n '--ck-shadow-modal': 'shadowModal',\n '--ck-shadow-card': 'shadowCard',\n\n // Overlay\n '--ck-overlay-color': 'overlayColor',\n}\n\nexport function appearanceToStyle(appearance?: Appearance): CSSProperties | undefined {\n const variables = appearance?.variables\n if (!variables) return undefined\n\n const style: Record<string, string> = {}\n for (const [cssProp, varKey] of Object.entries(VAR_MAP)) {\n const value = variables[varKey]\n if (value) style[cssProp] = value\n }\n\n return Object.keys(style).length > 0 ? (style as CSSProperties) : undefined\n}\n\n// Step-level fallback titles when neither token-mode config nor local\n// step config provide one. Offer and Success are absent — Offer falls back\n// to `offer.copy.headline`, Success branches on outcome.\nexport const defaultTitles = {\n survey: 'Why are you cancelling?',\n feedback: 'Any other feedback?',\n confirm: 'Confirm cancellation',\n} as const\n","import type { SdkConfig } from './api-types'\nimport type { SessionCredentials } from './token'\nimport type { DirectCustomer, DirectSubscription, Mode } from './types'\n\nconst DEFAULT_BASE_URL = 'https://api.churnkey.co/v1'\n\n// Wire enums accepted by the API. Literal unions so payload builders fail\n// at compile time if they emit a value outside the accepted set.\nexport type ApiStepType = 'OFFER' | 'SURVEY' | 'CONFIRM' | 'FREEFORM' | 'CUSTOM'\nexport type ApiOfferType =\n | 'DISCOUNT'\n | 'PAUSE'\n | 'PLAN_CHANGE'\n | 'TRIAL_EXTENSION'\n | 'CONTACT'\n | 'REDIRECT'\n | 'REBATE'\n | 'CUSTOM'\nexport type ApiPauseInterval = 'MONTH' | 'WEEK'\nexport type ApiCouponType = 'PERCENT' | 'AMOUNT'\nexport type ApiBillingInterval = 'DAY' | 'WEEK' | 'MONTH' | 'YEAR'\nexport type ApiMode = 'LIVE' | 'TEST' | 'SANDBOX'\n\n// Exhaustive switch so a new Mode member without a wire mapping fails to compile.\nexport function toApiMode(mode: Mode): ApiMode {\n switch (mode) {\n case 'live':\n return 'LIVE'\n case 'test':\n return 'TEST'\n case 'sandbox':\n return 'SANDBOX'\n }\n}\n\nexport interface StepViewed {\n stepType: ApiStepType\n // Populated iff stepType === 'CUSTOM' — holds the SDK step name.\n customStepType?: string\n guid?: string\n numChoices?: number\n start: string\n end?: string\n duration?: number\n}\n\nexport interface PresentedOffer {\n guid?: string\n offerType?: ApiOfferType\n // Populated iff offerType === 'CUSTOM' — holds the SDK offer name.\n customOfferType?: string\n accepted: boolean\n presentedAt: string\n acceptedAt?: string\n declinedAt?: string\n [key: string]: unknown\n}\n\nexport interface AcceptedOfferPayload {\n guid?: string\n offerType: ApiOfferType\n // Populated iff offerType === 'CUSTOM' — holds the SDK offer name.\n customOfferType?: string\n // Populated iff offerType === 'CUSTOM' — the result arg passed to\n // `onAccept(result)` from the custom offer component.\n customOfferResult?: Record<string, unknown>\n couponId?: string\n couponType?: ApiCouponType\n couponAmount?: number\n couponDuration?: number\n pauseDuration?: number\n pauseInterval?: ApiPauseInterval\n newPlanId?: string\n newPlanPrice?: number\n trialExtensionDays?: number\n redirectUrl?: string\n rebateAmount?: number\n}\n\nexport interface SessionCustomer {\n id: string\n email?: string\n subscriptionId?: string\n planId?: string\n planPrice?: number\n currency?: string\n billingInterval?: ApiBillingInterval\n created?: string\n onTrial?: boolean\n customAttributes?: Record<string, unknown>\n}\n\nexport interface SessionPayload {\n blueprintId?: string\n surveyId?: string\n customer?: SessionCustomer\n canceled?: boolean\n aborted?: boolean\n surveyChoiceId?: string\n surveyChoiceValue?: string\n /** Free-text from a `freeform: true` reason. The reason's static `label` still travels on `surveyChoiceValue`. */\n followupResponse?: string\n feedback?: string\n acceptedOffer?: AcceptedOfferPayload\n presentedOffers?: PresentedOffer[]\n stepsViewed?: StepViewed[]\n customStepResults?: Record<string, unknown>\n mode: ApiMode\n provider?: string\n embedVersion?: string\n // Token-mode session-record fields. Populated automatically when the SDK\n // is configured with a session token; ignored in local/analytics mode.\n clickToCancelEnabled?: boolean\n strictFTCComplianceEnabled?: boolean\n usedClickToCancel?: boolean\n autoOptimizationUsed?: boolean\n autoOptimizationKey?: string\n discountCooldown?: number\n pauseCooldown?: number\n discountCooldownApplied?: boolean\n pauseCooldownApplied?: boolean\n}\n\nexport class ChurnkeyApi {\n private creds: SessionCredentials\n private baseUrl: string\n\n constructor(creds: SessionCredentials, baseUrl?: string) {\n this.creds = creds\n this.baseUrl = baseUrl ?? DEFAULT_BASE_URL\n }\n\n private get headers(): Record<string, string> {\n const h: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-ck-app': this.creds.appId,\n 'x-ck-customer': this.creds.customerId,\n 'x-ck-authorization': this.creds.authHash,\n 'x-ck-mode': this.creds.mode,\n }\n if (this.creds.subscriptionId) {\n h['x-ck-subscription'] = this.creds.subscriptionId\n }\n return h\n }\n\n private orgUrl(path: string): string {\n return `${this.baseUrl}/api/orgs/${this.creds.appId}/${path}`\n }\n\n // Action methods discard the response body, so don't parse JSON here —\n // a server returning an empty 201 would otherwise blow up res.json() and\n // surface as an error even though the action committed.\n private async request(url: string, body?: unknown): Promise<Response> {\n const res = await fetch(url, {\n method: 'POST',\n headers: this.headers,\n body: body ? JSON.stringify(body) : undefined,\n })\n if (!res.ok) {\n const text = await res.text().catch(() => '')\n throw new Error(`Churnkey API error (${res.status}): ${text}`)\n }\n return res\n }\n\n // customAttributes feed server-side segment matching when the blueprint is\n // picked. The body must not also carry a Direct `customer` — that tells the\n // server to skip the provider lookup, and segments should match against the\n // real provider customer plus this attribute layer.\n async fetchConfig(customAttributes?: Record<string, unknown>): Promise<SdkConfig> {\n const res = await this.request(\n this.orgUrl('cancel-flow/config'),\n customAttributes ? { customAttributes } : undefined,\n )\n return (await res.json()) as SdkConfig\n }\n\n async applyDiscount(couponId: string, blueprintId?: string): Promise<void> {\n await this.request(this.orgUrl('cancel-flow/actions/discount'), {\n coupon: couponId,\n blueprintId,\n })\n }\n\n async pause(params: { duration: number; interval: string }): Promise<void> {\n await this.request(this.orgUrl('cancel-flow/actions/pause'), {\n duration: params.duration,\n interval: params.interval,\n })\n }\n\n async cancelSubscription(): Promise<void> {\n await this.request(this.orgUrl('cancel-flow/actions/cancel'), { cancelAtPeriodEnd: true })\n }\n\n async changePlan(planId: string): Promise<void> {\n await this.request(this.orgUrl('cancel-flow/actions/change-plan'), { planId })\n }\n\n async extendTrial(days: number, blueprintId?: string): Promise<void> {\n await this.request(this.orgUrl('cancel-flow/actions/extend-trial'), { days, blueprintId })\n }\n\n async applyRebate(blueprintId?: string, offerGuid?: string): Promise<void> {\n await this.request(this.orgUrl('cancel-flow/actions/rebate'), { blueprintId, offerGuid })\n }\n\n async createSession(payload: SessionPayload): Promise<void> {\n await this.request(`${this.baseUrl}/api/sessions/sdk`, payload)\n }\n}\n\nexport class AnalyticsClient {\n private appId: string\n private baseUrl: string\n\n constructor(appId: string, baseUrl?: string) {\n this.appId = appId\n this.baseUrl = baseUrl ?? DEFAULT_BASE_URL\n }\n\n // Fire-and-forget. Non-2xx responses are ignored — analytics failures\n // should never surface into the host app's flow.\n async createSession(payload: SessionPayload): Promise<void> {\n await fetch(`${this.baseUrl}/api/sessions/sdk`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-ck-app': this.appId,\n },\n body: JSON.stringify(payload),\n })\n }\n}\n\nfunction toIsoString(value: Date | string | undefined): string | undefined {\n if (value == null) return undefined\n return value instanceof Date ? value.toISOString() : String(value)\n}\n\nfunction toApiBillingInterval(interval: 'day' | 'week' | 'month' | 'year' | undefined): ApiBillingInterval | undefined {\n if (!interval) return undefined\n return interval.toUpperCase() as ApiBillingInterval\n}\n\nexport function directDataToSessionCustomer(\n customer: DirectCustomer,\n subscriptions?: DirectSubscription[],\n): SessionPayload['customer'] {\n const sub = subscriptions?.[0]\n const price = sub?.items[0]?.price\n\n return {\n id: customer.id,\n email: customer.email,\n subscriptionId: sub?.id,\n planId: price?.id,\n planPrice: price?.amount.value,\n currency: price?.amount.currency ?? customer.currency,\n billingInterval: toApiBillingInterval(price?.duration?.interval),\n created: toIsoString(sub?.start),\n onTrial: sub ? sub.status.name === 'trial' : undefined,\n customAttributes: customer.metadata,\n }\n}\n","// Merge field substitution for dashboard-authored copy. Placeholders look\n// like `{{CUSTOMER_NAME.FIRST|Jane}}` — field name, optional fallback after\n// the pipe. Copy can also arrive wrapped in `<merge-field>` tags (the\n// dashboard editor uses them for its own UI); browsers render unknown tags\n// as their text content, so the wrapper is transparent and only the inner\n// `{{…}}` needs substitution.\n\nimport type {\n DirectCustomer,\n FeedbackStep,\n OfferConfig,\n OfferDecision,\n OfferStep,\n ReasonConfig,\n Step,\n SurveyStep,\n} from './types'\n\nexport type MergeAttrs = Record<string, string>\n\nconst MERGE_FIELD_PATTERN = /{{([a-zA-Z0-9_.]+)\\|([^}]*)}}/g\n\n/**\n * Build the attribute map merge fields are resolved against. Sourced from\n * Direct.Customer fields: name (with `.FIRST`/`.LAST` variants), email, and\n * metadata, then the consumer's `customerAttributes` layer, which wins key\n * conflicts (same precedence as the embed). Values that aren't strings are\n * coerced — dashboards emit merge fields into HTML, and HTML only speaks\n * strings.\n */\nexport function buildMergeAttrs(\n customer: DirectCustomer | null | undefined,\n customerAttributes?: Record<string, unknown> | null,\n): MergeAttrs {\n const attrs: MergeAttrs = {}\n\n if (customer) {\n // Build full name from Direct.Customer's separate first/last name fields.\n const first = customer.name\n const last = customer.lastName\n const fullName = [first, last].filter(Boolean).join(' ') || undefined\n if (fullName) attrs.CUSTOMER_NAME = fullName\n if (first) attrs['CUSTOMER_NAME.FIRST'] = first\n if (last) attrs['CUSTOMER_NAME.LAST'] = last\n\n if (customer.email) attrs.CUSTOMER_EMAIL = customer.email\n\n for (const [key, value] of Object.entries(customer.metadata ?? {})) {\n if (value != null) attrs[key] = String(value)\n }\n }\n\n for (const [key, value] of Object.entries(customerAttributes ?? {})) {\n if (value != null) attrs[key] = String(value)\n }\n\n return attrs\n}\n\n/**\n * Replace `{{FIELD|fallback}}` placeholders in `text` with values from `attrs`.\n * Missing keys fall back to the `|…}}` segment (which may be empty). The\n * enclosing `<merge-field>` wrapper, if any, is left as-is — browsers ignore\n * unknown tags and render their children, so the visible output is correct.\n */\nexport function applyMergeFields(text: string, attrs: MergeAttrs): string {\n if (!text?.includes('{{')) return text\n return text.replace(MERGE_FIELD_PATTERN, (_match, field: string, fallback: string) => attrs[field] ?? fallback)\n}\n\n/**\n * Substitute merge fields across a Step[] tree. Called once at machine init\n * so the runtime carries already-resolved copy — components stay unaware of\n * merge fields entirely.\n */\nexport function applyMergeFieldsToSteps(\n steps: Step[],\n customer: DirectCustomer | null | undefined,\n customerAttributes?: Record<string, unknown> | null,\n): Step[] {\n const attrs = buildMergeAttrs(customer, customerAttributes)\n return steps.map((step) => mergeStep(step, attrs))\n}\n\nfunction mergeStep(step: Step, attrs: MergeAttrs): Step {\n // CustomStepConfig.type is `string`, so a literal-string switch doesn't\n // narrow it out of the union — each branch needs an explicit cast.\n switch (step.type) {\n case 'survey': {\n const s = step as SurveyStep\n return {\n ...s,\n title: maybeMerge(s.title, attrs),\n description: maybeMerge(s.description, attrs),\n reasons: s.reasons.map((r) => mergeReason(r, attrs)),\n }\n }\n case 'offer': {\n const s = step as OfferStep\n return {\n ...s,\n title: maybeMerge(s.title, attrs),\n description: maybeMerge(s.description, attrs),\n offer: s.offer ? mergeOffer(s.offer, attrs) : undefined,\n }\n }\n case 'feedback': {\n const s = step as FeedbackStep\n return {\n ...s,\n title: maybeMerge(s.title, attrs),\n description: maybeMerge(s.description, attrs),\n placeholder: maybeMerge(s.placeholder, attrs),\n }\n }\n case 'success':\n // savedTitle/cancelledTitle/etc. are picked at render time based on the\n // outcome; merge substitution can be added there if it's ever needed.\n return step\n default: {\n const s = step as { title?: string; description?: string }\n return { ...step, title: maybeMerge(s.title, attrs), description: maybeMerge(s.description, attrs) }\n }\n }\n}\n\nfunction mergeReason(r: ReasonConfig, attrs: MergeAttrs): ReasonConfig {\n return { ...r, label: applyMergeFields(r.label, attrs) }\n}\n\n// Standalone OfferSteps may arrive without copy (the step graph synthesizes\n// defaults later); merging copy is a no-op when there's nothing to merge.\nfunction mergeOffer(o: OfferConfig | OfferDecision, attrs: MergeAttrs): OfferConfig | OfferDecision {\n if (!('copy' in o)) return o\n return {\n ...o,\n copy: {\n headline: applyMergeFields(o.copy.headline, attrs),\n body: applyMergeFields(o.copy.body, attrs),\n cta: applyMergeFields(o.copy.cta, attrs),\n declineCta: applyMergeFields(o.copy.declineCta, attrs),\n },\n }\n}\n\nfunction maybeMerge(text: string | undefined, attrs: MergeAttrs): string | undefined {\n return text ? applyMergeFields(text, attrs) : text\n}\n","// Steps are a graph, not an array. Each step has a guid and two pointer\n// fields — defaultNextStep, defaultPreviousStep — set once at build and\n// never mutated. Survey steps additionally carry offersAttached, a\n// reasonId → synthetic-offer-step-guid map.\n//\n// Survey-choice offers are their own steps rather than a mutable slot, so\n// the current offer is always readable as stepMap[currentStepId].offer —\n// one source of truth for what's on screen.\n//\n// The graph is immutable after build. Local mode builds in the machine\n// constructor; token mode defers until the server config has loaded.\n\nimport type {\n ConfirmStep,\n CustomStepConfig,\n FeedbackStep,\n OfferConfig,\n OfferDecision,\n OfferStep,\n ReasonConfig,\n Step,\n SuccessStep,\n SurveyStep,\n} from './types'\n\nexport interface ResolvedStep {\n guid: string\n type: string\n defaultNextStep?: string\n defaultPreviousStep?: string\n title?: string\n description?: string\n\n // survey\n reasons?: ReasonConfig[]\n offersAttached?: Record<string, string>\n numChoices?: number\n\n // offer\n offer?: OfferDecision\n /** True if this step was synthesized from a survey choice. Used by stepIndex so synthetic offers share the survey's progress slot. */\n surveyOffer?: boolean\n\n // feedback\n placeholder?: string\n required?: boolean\n minLength?: number\n\n // confirm\n losses?: string[]\n lossesLabel?: string\n\n // success\n savedTitle?: string\n savedDescription?: string\n cancelledTitle?: string\n cancelledDescription?: string\n\n // custom\n data?: Record<string, unknown>\n\n classNames?: unknown\n}\n\nexport interface StepGraph {\n stepMap: Record<string, ResolvedStep>\n /** Entry point. */\n firstStepId: string\n /** Developer-declared steps in declaration order. Synthetic offer steps are NOT included — they live in stepMap only. Drives progress UI. */\n orderedStepIds: string[]\n /** Cached for O(1) lookup. Undefined if the flow has no survey step. */\n surveyStepId?: string\n}\n\nconst EMPTY_GRAPH: StepGraph = { stepMap: {}, firstStepId: '', orderedStepIds: [] }\n\nexport function buildStepGraph(\n steps: Step[],\n defaultOfferCopy: (offer: OfferConfig) => OfferDecision['copy'],\n): StepGraph {\n if (steps.length === 0) return EMPTY_GRAPH\n\n const resolved = steps.map((step, i) => normalizeStep(step, i, defaultOfferCopy))\n linkNeighbors(resolved)\n\n const stepMap: Record<string, ResolvedStep> = {}\n for (const step of resolved) stepMap[step.guid] = step\n\n // Only the first survey in the declared order gets its choice offers wired.\n // Multiple surveys per flow is legal but unusual; the second+ behave as\n // plain steps. If this becomes a real pattern, wire them all.\n const surveyStep = resolved.find((s) => s.type === 'survey')\n if (surveyStep?.reasons) {\n surveyStep.offersAttached = {}\n for (const reason of surveyStep.reasons) {\n if (!reason.offer) continue\n const offerGuid = `${surveyStep.guid}:offer:${reason.id}`\n stepMap[offerGuid] = {\n guid: offerGuid,\n type: 'offer',\n surveyOffer: true,\n offer: toDecision(reason.offer, defaultOfferCopy),\n // Decline/next from the synthetic offer skips the survey entirely;\n // back returns to the survey so the user can pick a different reason.\n defaultNextStep: surveyStep.defaultNextStep,\n defaultPreviousStep: surveyStep.guid,\n }\n surveyStep.offersAttached[reason.id] = offerGuid\n }\n }\n\n return {\n stepMap,\n firstStepId: resolved[0].guid,\n orderedStepIds: resolved.map((s) => s.guid),\n surveyStepId: surveyStep?.guid,\n }\n}\n\nfunction normalizeStep(\n step: Step,\n index: number,\n defaultOfferCopy: (offer: OfferConfig) => OfferDecision['copy'],\n): ResolvedStep {\n // Prefer the caller-provided guid; otherwise generate a stable slug. Stable\n // ids matter for analytics and React keys.\n const guid = (step as { guid?: string }).guid ?? `step-${index}-${step.type}`\n const base: ResolvedStep = { guid, type: step.type }\n\n switch (step.type) {\n case 'survey': {\n const s = step as SurveyStep\n return {\n ...base,\n title: s.title,\n description: s.description,\n reasons: s.reasons,\n numChoices: s.reasons.length,\n classNames: s.classNames,\n }\n }\n case 'offer': {\n const s = step as OfferStep\n return {\n ...base,\n title: s.title,\n description: s.description,\n // Standalone offers may arrive without `copy` — toDecision fills it\n // in from defaultOfferCopy. Token-mode offers already carry copy\n // from the server, so toDecision passes them through unchanged.\n offer: s.offer ? toDecision(s.offer, defaultOfferCopy) : undefined,\n classNames: s.classNames,\n }\n }\n case 'feedback': {\n const s = step as FeedbackStep\n return {\n ...base,\n title: s.title,\n description: s.description,\n placeholder: s.placeholder,\n required: s.required,\n minLength: s.minLength,\n classNames: s.classNames,\n }\n }\n case 'confirm': {\n const s = step as ConfirmStep\n return {\n ...base,\n title: s.title,\n description: s.description,\n losses: s.losses,\n lossesLabel: s.lossesLabel,\n classNames: s.classNames,\n }\n }\n case 'success': {\n const s = step as SuccessStep\n return {\n ...base,\n savedTitle: s.savedTitle,\n savedDescription: s.savedDescription,\n cancelledTitle: s.cancelledTitle,\n cancelledDescription: s.cancelledDescription,\n classNames: s.classNames,\n }\n }\n default: {\n const s = step as CustomStepConfig\n return {\n ...base,\n title: s.title,\n description: s.description,\n data: s.data,\n }\n }\n }\n}\n\nfunction linkNeighbors(steps: ResolvedStep[]): void {\n for (let i = 0; i < steps.length; i++) {\n if (i < steps.length - 1) steps[i].defaultNextStep = steps[i + 1].guid\n if (i > 0) steps[i].defaultPreviousStep = steps[i - 1].guid\n }\n}\n\nfunction toDecision(offer: OfferConfig, defaultCopy: (o: OfferConfig) => OfferDecision['copy']): OfferDecision {\n return 'copy' in offer ? (offer as OfferDecision) : { ...offer, copy: defaultCopy(offer) }\n}\n","// Translate the SdkConfig response (token mode) into the runtime Step shape\n// the rest of the SDK works with. Token-mode flows arrive with offers fully\n// resolved — coupon ids hydrated to amounts and durations, plan ids inlined\n// as DirectPrice[], so this layer is a pure shape projection.\n\nimport type { SdkConfig, SdkCustomOffer, SdkDiscountOffer, SdkOffer, SdkReason, SdkStep } from './api-types'\nimport type { BuiltInOfferConfig, OfferConfig, OfferCopy, OfferDecision, ReasonConfig, Step } from './types'\nimport { BUILT_IN_OFFER_TYPES } from './utils'\n\nexport interface TransformResult {\n steps: Step[]\n blueprintId: string\n metadata: {\n autoOptimizationKey?: string\n }\n}\n\nexport function transformSdkConfig(config: SdkConfig): TransformResult {\n return {\n steps: config.steps.map(transformStep),\n blueprintId: config.blueprintId,\n metadata: {\n autoOptimizationKey: config.autoOptimizationKey,\n },\n }\n}\n\nfunction transformStep(step: SdkStep): Step {\n switch (step.type) {\n case 'survey':\n return {\n type: 'survey',\n guid: step.guid,\n title: step.title,\n description: step.description,\n reasons: step.reasons.map(transformReason),\n }\n case 'offer':\n return {\n type: 'offer',\n guid: step.guid,\n title: step.title,\n description: step.description,\n offer: transformOfferDecision(step.offer),\n }\n case 'feedback':\n return {\n type: 'feedback',\n guid: step.guid,\n title: step.title,\n description: step.description,\n placeholder: step.placeholder,\n required: step.required,\n minLength: step.minLength,\n }\n case 'confirm':\n return {\n type: 'confirm',\n guid: step.guid,\n title: step.title,\n description: step.description,\n }\n }\n}\n\nfunction transformReason(r: SdkReason): ReasonConfig {\n const out: ReasonConfig = {\n id: r.id,\n label: r.label,\n }\n if (r.freeform) out.freeform = true\n if (r.offer) out.offer = transformOfferConfig(r.offer)\n return out\n}\n\nfunction transformOfferDecision(o: SdkOffer): OfferDecision {\n return { ...transformOfferConfig(o), copy: o.copy, decisionId: o.decisionId }\n}\n\nfunction transformOfferConfig(o: SdkOffer): OfferConfig {\n // Merchant-defined offers: `type` is the registered key and `data` the\n // builder's config. Pass both through untouched so the renderer can match\n // customComponents[type].\n if (!BUILT_IN_OFFER_TYPES.includes(o.type)) {\n const custom = o as unknown as SdkCustomOffer\n return custom.data !== undefined ? { type: custom.type, data: custom.data } : { type: custom.type }\n }\n switch (o.type) {\n case 'discount': {\n const d: SdkDiscountOffer = o\n return {\n type: 'discount',\n couponId: d.couponId,\n percentOff: d.percentOff,\n amountOff: d.amountOff,\n currency: d.currency,\n durationInMonths: d.durationInMonths,\n }\n }\n case 'pause':\n return {\n type: 'pause',\n months: o.months,\n interval: o.interval,\n }\n case 'plan_change':\n return {\n type: 'plan_change',\n plans: o.plans,\n }\n case 'trial_extension':\n return {\n type: 'trial_extension',\n days: o.days,\n }\n case 'redirect':\n return {\n type: 'redirect',\n url: o.url,\n label: o.label ?? '',\n }\n case 'contact':\n return {\n type: 'contact',\n url: o.url,\n label: o.label,\n }\n case 'rebate':\n return {\n type: 'rebate',\n amountMinor: o.amountMinor,\n currency: o.currency,\n amountPaidMinor: o.amountPaidMinor,\n netAfterRebateMinor: o.netAfterRebateMinor,\n paymentMethodBrand: o.paymentMethodBrand,\n paymentMethodLast4: o.paymentMethodLast4,\n }\n }\n}\n\n/**\n * Default offer copy used by step-graph.ts when a local-mode offer doesn't\n * include explicit copy. Token-mode offers come with copy already filled in\n * by the server, so this only fires for local mode.\n */\nexport function defaultOfferCopy(offer: OfferConfig): OfferCopy {\n const o = offer as BuiltInOfferConfig\n switch (o.type) {\n case 'discount':\n return {\n headline: o.percentOff != null ? `How about ${o.percentOff}% off?` : 'Special offer',\n body: discountBody(o),\n cta: 'Accept offer',\n declineCta: 'No thanks',\n }\n case 'pause':\n return {\n headline: 'Take a break instead?',\n body: `Pause your subscription for up to ${o.months} month${o.months === 1 ? '' : 's'}.`,\n cta: 'Pause subscription',\n declineCta: 'No thanks',\n }\n case 'plan_change':\n return {\n headline: 'Switch to a different plan?',\n body: 'We have other plans that might be a better fit.',\n cta: 'Switch plan',\n declineCta: 'No thanks',\n }\n case 'trial_extension':\n return {\n headline: 'Need more time?',\n body: `We'll extend your trial by ${o.days} day${o.days === 1 ? '' : 's'}.`,\n cta: 'Extend trial',\n declineCta: 'No thanks',\n }\n case 'contact':\n return {\n headline: 'Talk to us first?',\n body: 'Our team would love to help resolve any issues.',\n cta: o.label ?? 'Contact support',\n declineCta: 'No thanks',\n }\n case 'redirect':\n return {\n headline: 'Before you go...',\n body: 'Check this out — it might change your mind.',\n cta: o.label,\n declineCta: 'No thanks',\n }\n case 'rebate':\n return {\n headline: 'Get money back',\n body: \"Stay subscribed and we'll refund part of your most recent payment.\",\n cta: 'Accept refund',\n declineCta: 'No thanks',\n }\n default:\n return {\n headline: 'Before you go...',\n body: \"We'd like to offer you something.\",\n cta: 'Accept',\n declineCta: 'No thanks',\n }\n }\n}\n\nfunction discountBody(o: { percentOff?: number; durationInMonths?: number }): string {\n if (o.percentOff == null) return \"We'd like to offer you a discount.\"\n const months = o.durationInMonths ?? 1\n return `We'd like to offer you ${o.percentOff}% off for ${months} month${months === 1 ? '' : 's'}.`\n}\n","import type {\n AcceptedOfferPayload,\n ApiOfferType,\n ApiPauseInterval,\n ApiStepType,\n ChurnkeyApi,\n PresentedOffer,\n SessionPayload,\n StepViewed,\n} from './api'\nimport { AnalyticsClient, directDataToSessionCustomer, toApiMode } from './api'\nimport type { SdkConfig } from './api-types'\nimport { applyMergeFieldsToSteps } from './merge-fields'\nimport { buildStepGraph, type ResolvedStep, type StepGraph } from './step-graph'\nimport type { SessionCredentials } from './token'\nimport { defaultOfferCopy, transformSdkConfig } from './transform'\nimport type {\n AcceptedOffer,\n BuiltInOfferConfig,\n BuiltInStepType,\n DirectCustomer,\n DirectSubscription,\n FlowCallbacks,\n FlowConfig,\n FlowState,\n Mode,\n OfferDecision,\n ReasonConfig,\n Step,\n} from './types'\n\ntype OfferCallback = (offer: AcceptedOffer, customer: DirectCustomer | null) => Promise<void> | void\n\nfunction handlerFor(offerType: string, cb: FlowCallbacks): OfferCallback | undefined {\n switch (offerType) {\n case 'discount':\n return cb.handleDiscount\n case 'pause':\n return cb.handlePause\n case 'plan_change':\n return cb.handlePlanChange\n case 'trial_extension':\n return cb.handleTrialExtension\n case 'rebate':\n return cb.handleRebate\n default:\n return undefined\n }\n}\n\nfunction listenerFor(offerType: string, cb: FlowCallbacks): OfferCallback | undefined {\n switch (offerType) {\n case 'discount':\n return cb.onDiscount\n case 'pause':\n return cb.onPause\n case 'plan_change':\n return cb.onPlanChange\n case 'trial_extension':\n return cb.onTrialExtension\n case 'rebate':\n return cb.onRebate\n default:\n return undefined\n }\n}\n\n// Listener errors are swallowed — they're side effects, not part of the\n// success path, and shouldn't flip the flow into an error state.\nfunction runListener(listener: OfferCallback, offer: AcceptedOffer, customer: DirectCustomer | null): Promise<void> {\n return Promise.resolve(listener(offer, customer)).catch((e) => {\n console.error('Error in offer listener:', e)\n })\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (!value || typeof value !== 'object') return false\n const proto = Object.getPrototypeOf(value)\n return proto === null || proto === Object.prototype\n}\n\n// --- Wire translation ---\n//\n// SDK types use lowercase identifiers; the API expects uppercase enums.\n// Both maps are typed as exhaustive Records so adding a new built-in step\n// or offer type fails the build until its wire mapping is set.\nconst STEP_TYPE_API_MAP: Record<Exclude<BuiltInStepType, 'success'>, Exclude<ApiStepType, 'CUSTOM'>> = {\n survey: 'SURVEY',\n offer: 'OFFER',\n feedback: 'FREEFORM',\n confirm: 'CONFIRM',\n}\n\nconst OFFER_TYPE_API_MAP: Record<BuiltInOfferConfig['type'], Exclude<ApiOfferType, 'CUSTOM'>> = {\n discount: 'DISCOUNT',\n pause: 'PAUSE',\n plan_change: 'PLAN_CHANGE',\n trial_extension: 'TRIAL_EXTENSION',\n contact: 'CONTACT',\n redirect: 'REDIRECT',\n rebate: 'REBATE',\n}\n\n// 'success' isn't a stepsViewed entry — the session's outcome/canceled/\n// acceptedOffer already captures the terminal state, and recording it\n// separately would double-count the funnel's last hop.\nfunction toApiStepType(step: string): { stepType: ApiStepType; customStepType?: string } | null {\n if (step === 'success') return null\n const builtIn = STEP_TYPE_API_MAP[step as Exclude<BuiltInStepType, 'success'>]\n if (builtIn) return { stepType: builtIn }\n return { stepType: 'CUSTOM', customStepType: step }\n}\n\nfunction toApiOfferType(type: string): { offerType: ApiOfferType; customOfferType?: string } {\n const builtIn = OFFER_TYPE_API_MAP[type as BuiltInOfferConfig['type']]\n if (builtIn) return { offerType: builtIn }\n return { offerType: 'CUSTOM', customOfferType: type }\n}\n\nfunction toApiPauseInterval(interval: 'month' | 'week' | undefined): ApiPauseInterval {\n return interval === 'week' ? 'WEEK' : 'MONTH'\n}\n\n// --- Offer shape builders ---\n//\n// Sessions record offers two ways: presentedOffers keeps the nested config\n// shape (discountConfig, pauseConfig, …); acceptedOffer flattens the fields.\n// Two builders, one source of truth.\n\nfunction toPresentedOfferConfig(rec: OfferDecision): Partial<PresentedOffer> {\n const base = toApiOfferType(rec.type)\n if (base.offerType === 'CUSTOM') return base\n const o = rec as BuiltInOfferConfig\n switch (o.type) {\n case 'discount':\n return {\n ...base,\n discountConfig: { couponId: o.couponId, customAmount: o.percentOff },\n }\n case 'pause':\n return {\n ...base,\n pauseConfig: {\n maxPauseLength: o.months,\n pauseInterval: toApiPauseInterval(o.interval),\n },\n }\n case 'plan_change':\n return { ...base, planChangeConfig: {} }\n case 'trial_extension':\n return { ...base, trialExtensionConfig: { trialExtensionDays: o.days } }\n case 'redirect':\n return {\n ...base,\n redirectConfig: { redirectUrl: o.url, redirectLabel: o.label },\n }\n case 'contact':\n return { ...base, contactConfig: {} }\n default:\n return base\n }\n}\n\nfunction toAcceptedOfferPayload(rec: OfferDecision, result?: Record<string, unknown>): AcceptedOfferPayload {\n const base: AcceptedOfferPayload = { guid: rec.decisionId, ...toApiOfferType(rec.type) }\n if (base.offerType === 'CUSTOM') {\n return result ? { ...base, customOfferResult: result } : base\n }\n const o = rec as BuiltInOfferConfig\n switch (o.type) {\n case 'discount':\n return {\n ...base,\n couponId: o.couponId,\n couponAmount: o.percentOff,\n couponType: 'PERCENT',\n couponDuration: o.durationInMonths,\n }\n case 'pause':\n return {\n ...base,\n pauseDuration: o.months,\n pauseInterval: toApiPauseInterval(o.interval),\n }\n case 'plan_change':\n return {\n ...base,\n newPlanId: o.plans?.[0]?.id,\n newPlanPrice: o.plans?.[0]?.amount.value,\n }\n case 'trial_extension':\n return { ...base, trialExtensionDays: o.days }\n case 'redirect':\n return { ...base, redirectUrl: o.url }\n case 'rebate':\n return { ...base, rebateAmount: o.amountMinor }\n default:\n return base\n }\n}\n\n// --- Machine ---\n\nexport class CancelFlowMachine {\n private state: FlowState\n private cachedSnapshot: FlowState\n private callbacks: FlowCallbacks\n private graph: StepGraph = { stepMap: {}, firstStepId: '', orderedStepIds: [] }\n private listeners: Set<() => void> = new Set()\n\n private apiClient: ChurnkeyApi | null = null\n private analyticsClient: AnalyticsClient | null = null\n private directCustomer: DirectCustomer | null = null\n private directSubscriptions: DirectSubscription[] | null = null\n private customerAttributes: Record<string, unknown> | null = null\n private creds: SessionCredentials | null = null\n private config: SdkConfig | null = null\n private blueprintId: string | null = null\n private localSteps: Step[] | null = null\n private stepsViewed: StepViewed[] = []\n private presentedOffers: PresentedOffer[] = []\n private customStepResults: Record<string, unknown> = {}\n private configMode: Mode = 'live'\n private stepEnteredAt: number = Date.now()\n private aborted = false\n // Visited-step stack. `back` pops this so it lands on the actually-seen\n // previous step (including synthetic offers a survey choice spawned),\n // not the previous step in declared graph order.\n private history: string[] = []\n\n constructor(config: FlowConfig) {\n // FlowConfig extends FlowCallbacks; storing the whole config covers\n // every callback by name without a separate copy.\n this.callbacks = config\n if (config.mode) this.configMode = config.mode\n if (config.customerAttributes) this.customerAttributes = config.customerAttributes\n if (config.appId && config.customer) {\n this.analyticsClient = new AnalyticsClient(config.appId, config.apiBaseUrl)\n this.directCustomer = config.customer\n this.directSubscriptions = config.subscriptions ?? null\n }\n\n // Token mode defers graph construction until initializeFromConfig runs\n // with the server-supplied steps; stash any locally-declared steps for\n // merging then.\n if (config.session) {\n if (config.steps) this.localSteps = config.steps\n } else if (config.steps) {\n const merged = applyMergeFieldsToSteps(config.steps, this.directCustomer, this.customerAttributes)\n this.graph = buildStepGraph(merged, defaultOfferCopy)\n }\n\n // Seed state from local props for open-source and analytics modes. Token\n // mode overwrites both fields once initializeFromConfig settles, so these\n // values only matter for the pre-fetch render.\n this.state = this.buildInitialState(this.directCustomer, this.directSubscriptions ?? [])\n this.cachedSnapshot = { ...this.state }\n\n // Defer entry tracking in token mode — firing trackStepEnter before the\n // graph is built would record a stale (empty) guid.\n const first = this.firstStep()\n if (!config.session && first) this.trackStepEnter(first)\n }\n\n // Public methods are arrow-bound so consumers can pass them directly\n // (`<button onClick={flow.next}>`) and so useSyncExternalStore sees\n // stable references between renders.\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n getSnapshot = (): FlowState => {\n return this.cachedSnapshot\n }\n\n get reasons(): ReasonConfig[] {\n return this.surveyStep()?.reasons ?? []\n }\n\n get currentStep(): ResolvedStep | undefined {\n return this.graph.stepMap[this.state.currentStepId]\n }\n\n /** The offer on the current step, or null. Always derived — no separate slot to drift. */\n get currentOffer(): OfferDecision | null {\n return this.currentStep?.offer ?? null\n }\n\n /** Whether `back()` would move anywhere — false on the first step and on success. */\n get canGoBack(): boolean {\n if (this.state.step === 'success') return false\n return this.history.length > 0 || Boolean(this.currentStep?.defaultPreviousStep)\n }\n\n /**\n * First step of a given type. Fine for the common \"one step per type\" case;\n * flows with multiple of a type should key on currentStepId instead.\n */\n getStepConfig(stepType: string): ResolvedStep | undefined {\n return Object.values(this.graph.stepMap).find((s) => s.type === stepType)\n }\n\n /** Progress indicator index. Synthetic offers share their survey's slot. */\n get stepIndex(): number {\n const current = this.currentStep\n if (!current) return 0\n if (current.surveyOffer) {\n const surveyId = current.defaultPreviousStep\n return surveyId ? this.graph.orderedStepIds.indexOf(surveyId) : 0\n }\n return Math.max(0, this.graph.orderedStepIds.indexOf(current.guid))\n }\n\n get totalSteps(): number {\n return this.graph.orderedStepIds.length\n }\n\n selectReason = (id: string): void => {\n if (!this.reasons.find((r) => r.id === id)) return\n // Clear follow-up text on reason change so it doesn't carry across selections.\n this.setState({ selectedReason: id, followupResponse: '' })\n }\n\n setFollowupResponse = (text: string): void => {\n this.setState({ followupResponse: text })\n }\n\n next = (result?: Record<string, unknown>): void => {\n // `onClick={next}` would otherwise pass a SyntheticEvent through as result\n // — has circular refs, breaks JSON.stringify. Only accept plain objects.\n if (isPlainObject(result)) {\n this.customStepResults[this.state.step] = result\n }\n const nextId = this.projectedNextStepId()\n if (!nextId) return\n this.transitionTo(nextId, { recordHistory: true })\n }\n\n back = (): void => {\n const popped = this.history.pop()\n if (popped) {\n this.transitionTo(popped)\n return\n }\n // History is empty when the consumer triggered back without a prior\n // forward navigation (e.g. starting state). Fall back to declared order.\n const prevId = this.currentStep?.defaultPreviousStep\n if (prevId) this.transitionTo(prevId)\n }\n\n accept = async (result?: Record<string, unknown>): Promise<void> => {\n // Capture before any state transition — the 'success' transition may\n // move currentStepId off the offer step, depending on whether a success\n // step is declared in the graph.\n const offer = this.currentOffer\n if (!offer) return\n const safeResult = isPlainObject(result) ? result : undefined\n this.setState({ isProcessing: true, error: null })\n try {\n const acceptedOffer = this.buildAcceptedOffer(offer, safeResult)\n const customer = this.state.customer\n\n // Handler wins over the server-side action. With no handler, token mode\n // hits the server endpoint and local mode is a no-op (relying on\n // onAccept's catch-all if anything).\n const handler = handlerFor(offer.type, this.callbacks)\n if (handler) {\n await handler(acceptedOffer, customer)\n } else if (this.isTokenMode()) {\n await this.executeTokenAction(acceptedOffer, offer.decisionId)\n }\n\n // Listeners fire after the action succeeded, regardless of who ran it.\n // Per-type listener first, then the catch-all onAccept.\n const listener = listenerFor(offer.type, this.callbacks)\n if (listener) await runListener(listener, acceptedOffer, customer)\n await this.callbacks.onAccept?.(acceptedOffer, customer)\n\n this.markCurrentOfferAccepted()\n this.enterSuccessStep('saved')\n this.recordOutcome('saved', offer, safeResult)\n } catch (error) {\n this.setState({ isProcessing: false, error: error as Error })\n }\n }\n\n decline = (): void => {\n this.markCurrentOfferDeclined()\n const nextId = this.currentStep?.defaultNextStep\n if (nextId) this.transitionTo(nextId, { recordHistory: true })\n }\n\n setFeedback = (text: string): void => {\n this.setState({ feedback: text })\n }\n\n cancel = async (): Promise<void> => {\n this.setState({ isProcessing: true, error: null })\n try {\n const customer = this.state.customer\n\n if (this.callbacks.handleCancel) {\n await this.callbacks.handleCancel(customer)\n } else if (this.isTokenMode()) {\n await this.apiClient!.cancelSubscription()\n }\n\n await this.callbacks.onCancel?.(customer)\n this.enterSuccessStep('cancelled')\n this.recordOutcome('cancelled')\n } catch (error) {\n this.setState({ isProcessing: false, error: error as Error })\n }\n }\n\n close = (): void => {\n if (this.state.outcome === null && !this.aborted) {\n this.aborted = true\n this.recordAbort()\n }\n this.callbacks.onClose?.()\n }\n\n destroy(): void {\n this.listeners.clear()\n }\n\n // Callbacks are wired through the constructor; this only takes the\n // server-supplied config so callers can't accidentally clobber them.\n initializeFromConfig(config: SdkConfig, apiClient: ChurnkeyApi, creds: SessionCredentials): void {\n this.apiClient = apiClient\n this.creds = creds\n this.config = config\n\n const result = transformSdkConfig(config)\n this.blueprintId = result.blueprintId\n\n const merged = this.localSteps ? mergeLocalSteps(result.steps, this.localSteps) : result.steps\n const steps = applyMergeFieldsToSteps(merged, config.customer ?? null, this.customerAttributes)\n this.graph = buildStepGraph(steps, defaultOfferCopy)\n\n this.state = this.buildInitialState(config.customer ?? null, config.subscriptions ?? [])\n this.cachedSnapshot = { ...this.state }\n const first = this.firstStep()\n if (first) this.trackStepEnter(first)\n this.notify()\n }\n\n // --- Internal helpers ---\n\n private isTokenMode(): boolean {\n return this.apiClient != null\n }\n\n private firstStep(): ResolvedStep | undefined {\n return this.graph.stepMap[this.graph.firstStepId]\n }\n\n private surveyStep(): ResolvedStep | undefined {\n return this.graph.surveyStepId ? this.graph.stepMap[this.graph.surveyStepId] : undefined\n }\n\n private buildInitialState(customer: DirectCustomer | null, subscriptions: DirectSubscription[]): FlowState {\n const first = this.firstStep()\n return {\n step: first?.type ?? 'survey',\n currentStepId: this.graph.firstStepId,\n selectedReason: null,\n followupResponse: '',\n feedback: '',\n outcome: null,\n isProcessing: false,\n error: null,\n customer,\n subscriptions,\n }\n }\n\n // On a survey step with a selected reason that has an attached offer,\n // jump to that offer's synthetic step; otherwise follow the default\n // forward pointer.\n private projectedNextStepId(): string | undefined {\n const current = this.currentStep\n if (!current) return undefined\n if (current.offersAttached && this.state.selectedReason) {\n const override = current.offersAttached[this.state.selectedReason]\n if (override) return override\n }\n return current.defaultNextStep\n }\n\n // Single entry point for step changes. All navigation flows through here so\n // view-timing and presentation tracking stay in one place. Forward callers\n // pass recordHistory; `back` omits it so popping isn't reversed.\n private transitionTo(stepId: string, opts: { recordHistory?: boolean } = {}): void {\n const step = this.graph.stepMap[stepId]\n if (!step) return\n if (opts.recordHistory && this.state.currentStepId && this.state.currentStepId !== stepId) {\n this.history.push(this.state.currentStepId)\n }\n this.setState({ step: step.type, currentStepId: stepId })\n }\n\n private setState(partial: Partial<FlowState>): void {\n const prevStep = this.state.step\n this.state = { ...this.state, ...partial }\n this.cachedSnapshot = { ...this.state }\n if (partial.step && partial.step !== prevStep) {\n this.finalizeStepView(prevStep)\n // enterSuccessStep can set state.step='success' without moving currentStepId\n // (when no success step is declared). Only feed the new graph node into\n // trackStepEnter when its type actually matches — otherwise the prior\n // step would be re-recorded.\n const step = this.graph.stepMap[this.state.currentStepId]\n if (step?.type === partial.step) this.trackStepEnter(step)\n else this.trackStepView(partial.step)\n this.callbacks.onStepChange?.(partial.step, prevStep)\n }\n this.notify()\n }\n\n private trackStepEnter(step: ResolvedStep): void {\n this.trackStepView(step.type, step.guid, step.numChoices)\n if (step.type === 'offer') this.recordOfferPresented()\n }\n\n private recordOfferPresented(): void {\n const offer = this.currentOffer\n if (!offer) return\n this.presentedOffers.push({\n ...toPresentedOfferConfig(offer),\n guid: offer.decisionId,\n accepted: false,\n presentedAt: new Date().toISOString(),\n })\n }\n\n private markCurrentOfferAccepted(): void {\n const last = this.presentedOffers[this.presentedOffers.length - 1]\n if (!last || last.acceptedAt || last.declinedAt) return\n last.accepted = true\n last.acceptedAt = new Date().toISOString()\n }\n\n private markCurrentOfferDeclined(): void {\n const last = this.presentedOffers[this.presentedOffers.length - 1]\n if (!last || last.acceptedAt || last.declinedAt) return\n last.declinedAt = new Date().toISOString()\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener()\n }\n }\n\n private async executeTokenAction(offer: AcceptedOffer, decisionId?: string): Promise<void> {\n if (!this.apiClient) return\n\n // Only built-in offer types have a server action; custom types route\n // entirely through the consumer's handler/onAccept.\n const o = offer as BuiltInOfferConfig\n switch (o.type) {\n case 'discount':\n if (o.couponId) {\n await this.apiClient.applyDiscount(o.couponId, this.blueprintId ?? undefined)\n }\n break\n case 'pause':\n await this.apiClient.pause({ duration: o.months, interval: o.interval ?? 'month' })\n break\n case 'plan_change':\n await this.apiClient.changePlan(o.plans[0]?.id)\n break\n case 'trial_extension':\n await this.apiClient.extendTrial(o.days, this.blueprintId ?? undefined)\n break\n case 'rebate':\n await this.apiClient.applyRebate(this.blueprintId ?? undefined, decisionId)\n break\n }\n }\n\n private trackStepView(stepType: string, guid?: string, numChoices?: number): void {\n this.stepEnteredAt = Date.now()\n const mapped = toApiStepType(stepType)\n if (!mapped) return\n\n const entry: StepViewed = {\n ...mapped,\n start: new Date().toISOString(),\n }\n if (guid) entry.guid = guid\n if (numChoices != null) entry.numChoices = numChoices\n\n this.stepsViewed.push(entry)\n }\n\n private finalizeStepView(step: string): void {\n const mapped = toApiStepType(step)\n if (!mapped) return\n // Match the most recent entry for this step. Custom steps share\n // stepType='CUSTOM', so disambiguate on customStepType.\n const entry = [...this.stepsViewed]\n .reverse()\n .find((s) => s.stepType === mapped.stepType && s.customStepType === mapped.customStepType)\n if (entry) {\n entry.end = new Date().toISOString()\n entry.duration = Date.now() - this.stepEnteredAt\n }\n }\n\n // Offer passed in so accept() can capture it before enterSuccessStep\n // potentially moves currentStepId off the offer step. copy and decisionId\n // are SDK-internal — strip them from the consumer-facing payload.\n private buildAcceptedOffer(offer: OfferDecision, result?: Record<string, unknown>): AcceptedOffer {\n const { copy: _copy, decisionId: _decisionId, ...offerConfig } = offer\n const accepted: AcceptedOffer = offerConfig\n if (this.state.selectedReason) accepted.reasonId = this.state.selectedReason\n if (result) accepted.result = result\n return accepted\n }\n\n // Terminal transition. Prefer moving currentStepId to a declared success\n // step so the developer's savedTitle / classNames / custom component\n // applies; otherwise stay put and the renderer's defaults cover it.\n private enterSuccessStep(outcome: 'saved' | 'cancelled'): void {\n const success = this.getStepConfig('success')\n const partial: Partial<FlowState> = { step: 'success', outcome, isProcessing: false }\n if (success) partial.currentStepId = success.guid\n this.setState(partial)\n }\n\n private resolveSessionCustomer(): SessionPayload['customer'] {\n const direct = this.directCustomer\n ? directDataToSessionCustomer(this.directCustomer, this.directSubscriptions ?? undefined)\n : undefined\n // The consumer's attribute layer wins key conflicts with customer.metadata,\n // matching merge-field precedence and the embed's session shape.\n const customAttributes = this.customerAttributes\n ? { ...direct?.customAttributes, ...this.customerAttributes }\n : direct?.customAttributes\n // Token identifies the customer authoritatively; direct data fills in\n // extras (email, plan, metadata) but never overrides id/subscriptionId.\n if (this.creds) {\n return { ...direct, customAttributes, id: this.creds.customerId, subscriptionId: this.creds.subscriptionId }\n }\n return direct ? { ...direct, customAttributes } : undefined\n }\n\n private buildBasePayload(): SessionPayload {\n const selectedReason = this.reasons.find((r) => r.id === this.state.selectedReason)\n // surveyChoiceValue is always the static label so dashboard groupings\n // by reason stay stable. Typed text from `freeform: true` reasons\n // travels separately on followupResponse, mirroring the embed payload.\n const followupResponse =\n selectedReason?.freeform && this.state.followupResponse ? this.state.followupResponse : undefined\n const payload: SessionPayload = {\n blueprintId: this.blueprintId ?? undefined,\n customer: this.resolveSessionCustomer(),\n canceled: false,\n surveyChoiceId: this.state.selectedReason ?? undefined,\n surveyChoiceValue: selectedReason?.label,\n followupResponse,\n feedback: this.state.feedback || undefined,\n presentedOffers: this.presentedOffers,\n stepsViewed: this.stepsViewed,\n customStepResults: Object.keys(this.customStepResults).length > 0 ? this.customStepResults : undefined,\n // Token's signed mode wins — the client can't override it.\n mode: toApiMode(this.creds?.mode ?? this.configMode),\n provider: this.isTokenMode() ? undefined : 'sdk-react',\n embedVersion: 'sdk-react',\n }\n\n // Token-mode session-record fields. Required by downstream analytics\n // and compliance reporting on the dashboard.\n if (this.config) {\n const surveyStep = this.config.steps.find((s) => s.type === 'survey')\n payload.surveyId = surveyStep?.guid\n payload.clickToCancelEnabled = this.config.settings.clickToCancelEnabled\n payload.strictFTCComplianceEnabled = this.config.settings.strictFTCComplianceEnabled\n payload.usedClickToCancel = false\n payload.autoOptimizationUsed = !!this.config.autoOptimizationKey\n payload.autoOptimizationKey = this.config.autoOptimizationKey\n payload.discountCooldown = this.config.settings.discountCooldown\n payload.pauseCooldown = this.config.settings.pauseCooldown\n payload.discountCooldownApplied = false\n payload.pauseCooldownApplied = false\n }\n\n return payload\n }\n\n private recordAbort(): void {\n const client = this.apiClient ?? this.analyticsClient\n if (!client) return\n this.finalizeStepView(this.state.step)\n client.createSession({ ...this.buildBasePayload(), aborted: true }).catch(() => {})\n }\n\n // acceptedOffer is a parameter so callers capture it before enterSuccessStep\n // moves currentStepId off the offer step. setState already finalized the\n // step view on the way to 'success', so no extra finalize call here.\n private recordOutcome(\n outcome: 'saved' | 'cancelled',\n acceptedOffer?: OfferDecision,\n result?: Record<string, unknown>,\n ): void {\n const client = this.apiClient ?? this.analyticsClient\n if (!client) return\n\n const payload = this.buildBasePayload()\n payload.canceled = outcome === 'cancelled'\n\n if (outcome === 'saved' && acceptedOffer) {\n payload.acceptedOffer = toAcceptedOfferPayload(acceptedOffer, result)\n }\n\n client.createSession(payload).catch(() => {})\n }\n}\n\n// Local steps override server steps by type. Unmatched local steps append\n// at the end. Server order is preserved so the dashboard stays in charge of\n// flow shape while developers can swap in their own copy / custom steps.\nfunction mergeLocalSteps(serverSteps: Step[], localSteps: Step[]): Step[] {\n const localByType = new Map(localSteps.map((s) => [s.type, s]))\n const merged = serverSteps.map((serverStep) => {\n const local = localByType.get(serverStep.type)\n if (!local) return serverStep\n localByType.delete(serverStep.type)\n return { ...serverStep, ...local } as Step\n })\n for (const [, step] of localByType) merged.push(step)\n return merged\n}\n","import type { ComponentType, ReactElement, ReactNode } from 'react'\n\n// ─── Direct shape — billing data passed in and out of the SDK ─────────────\n//\n// Used both for consumer-supplied props (customer, subscriptions) and for\n// data the SDK receives in token mode, so there's no translation layer in\n// between. Provider-agnostic and intentionally minimal — only the fields the\n// cancel flow needs to render and record sessions.\n\nexport interface DirectAddress {\n line1?: string\n line2?: string\n city?: string\n state?: string\n postalCode?: string\n /** ISO 3166-1 alpha-2 */\n country?: string\n}\n\nexport interface DirectCustomer {\n id: string\n email?: string\n name?: string\n lastName?: string\n phone?: string\n /** ISO 4217 */\n currency?: string\n addresses?: DirectAddress[]\n metadata?: Record<string, unknown>\n}\n\nexport interface DirectPrice {\n id: string\n type?: 'standalone' | 'product'\n active?: boolean\n productId?: string\n name?: string\n description?: string\n duration?: {\n interval: 'day' | 'week' | 'month' | 'year'\n intervalCount?: number\n }\n amount: {\n model?: 'fixed' | 'tiered'\n /** Smallest currency unit (cents for USD). */\n value: number\n currency?: string\n }\n metadata?: Record<string, unknown>\n}\n\nexport interface DirectCoupon {\n id?: string\n name?: string\n percentOff?: number\n /** Smallest currency unit (cents for USD). */\n amountOff?: number\n currency?: string\n duration?: 'once' | 'repeating' | 'forever'\n durationInMonths?: number\n metadata?: Record<string, unknown>\n}\n\nexport type SubscriptionStatus =\n | { name: 'active'; currentPeriod: { start: Date | string; end: Date | string } }\n | {\n name: 'trial'\n trial: { start: Date | string; end: Date | string }\n currentPeriod?: { start: Date | string; end: Date | string }\n }\n | {\n name: 'paused'\n pause: { start: Date | string; end?: Date | string }\n currentPeriod?: { start: Date | string; end: Date | string }\n }\n | { name: 'canceled'; canceledAt: Date | string }\n | { name: 'unpaid'; currentPeriod?: { start: Date | string; end: Date | string } }\n | { name: 'future'; currentPeriod?: { start: Date | string; end: Date | string } }\n\nexport interface DirectSubscriptionItem {\n id?: string\n price: DirectPrice\n quantity?: number\n}\n\nexport interface DirectSubscription {\n id: string\n customerId?: string\n start: Date | string\n status: SubscriptionStatus\n items: DirectSubscriptionItem[]\n duration?: {\n interval: 'day' | 'week' | 'month' | 'year'\n intervalCount?: number\n }\n end?: Date | string\n discounts?: Array<{\n id?: string\n coupon?: DirectCoupon\n start?: Date | string\n end?: Date | string\n }>\n metadata?: Record<string, unknown>\n}\n\n// ─── Offers ──────────────────────────────────────────────────────────────────\n//\n// Local-mode developers write the same offer shape the SDK receives in\n// token mode, so behavior is consistent across modes.\n\nexport interface DiscountOffer {\n type: 'discount'\n couponId?: string\n percentOff?: number\n /** Smallest currency unit (cents for USD). */\n amountOff?: number\n currency?: string\n durationInMonths?: number\n}\n\nexport interface PauseOffer {\n type: 'pause'\n months: number\n interval?: 'month' | 'week'\n}\n\nexport interface PlanChangeOffer {\n type: 'plan_change'\n plans: PlanOption[]\n}\n\n/**\n * Plan option in a `plan_change` offer — `DirectPrice` plus optional\n * cancel-flow merchandising fields. Marketing fields are presentation-only\n * and live on `PlanOption` rather than `DirectPrice` so `Direct` stays a\n * clean billing-data shape reusable outside the cancel-flow context.\n */\nexport interface PlanOption extends DirectPrice {\n /** Short marketing line (e.g. \"Most popular\"). */\n tagline?: string\n /** Bullet list of plan features shown on the card. */\n features?: string[]\n /** Pre-formatted \"before\" price rendered struck-through (e.g. \"$49/mo\"). */\n msrp?: string\n}\n\nexport interface TrialExtensionOffer {\n type: 'trial_extension'\n days: number\n}\n\nexport interface ContactOffer {\n type: 'contact'\n url?: string\n label?: string\n}\n\nexport interface RedirectOffer {\n type: 'redirect'\n url: string\n label: string\n}\n\nexport interface RebateOffer {\n type: 'rebate'\n /** The rebate amount (pre-tax), smallest currency unit. The card is refunded this plus any tax charged on it. */\n amountMinor: number\n currency: string\n /** Gross paid on the target invoice. Server-resolved in token mode. */\n amountPaidMinor?: number\n /** amountPaidMinor minus the full refund (the rebate plus its tax). Server-resolved in token mode. */\n netAfterRebateMinor?: number\n paymentMethodBrand?: string\n paymentMethodLast4?: string\n}\n\nexport interface CustomOfferConfig {\n type: string\n data?: Record<string, unknown>\n}\n\nexport type BuiltInOfferConfig =\n | DiscountOffer\n | PauseOffer\n | PlanChangeOffer\n | TrialExtensionOffer\n | ContactOffer\n | RedirectOffer\n | RebateOffer\nexport type OfferConfig = BuiltInOfferConfig | CustomOfferConfig\n\nexport type OfferDecision = OfferConfig & { copy: OfferCopy; decisionId?: string }\n\nexport interface OfferCopy {\n headline: string\n /**\n * May contain HTML when the flow was authored in the Churnkey dashboard\n * (the description editor is rich text). Render with the exported\n * `RichText` component — the same renderer the built-in steps use — rather\n * than as a text node, or the markup shows escaped.\n */\n body: string\n cta: string\n declineCta: string\n}\n\nexport type AcceptedOffer = OfferConfig & {\n /** Survey reason that routed to this offer. Absent when the offer was\n * declared as a standalone `OfferStep`. */\n reasonId?: string\n /** Payload from custom offers — whatever your component passed to\n * `onAccept(result)`. Built-in offer types do not populate this. */\n result?: Record<string, unknown>\n}\n\n// ─── Reasons ─────────────────────────────────────────────────────────────────\n\nexport interface ReasonConfig {\n id: string\n label: string\n /**\n * When true, picking this reason reveals a text input below the reason list.\n * The typed text lands on the session as `followupResponse`. `surveyChoiceId`\n * still carries the reason's `id` and `surveyChoiceValue` still carries the\n * static `label`, so analytics groupings stay stable.\n */\n freeform?: boolean\n offer?: OfferConfig\n}\n\n// ─── Steps ───────────────────────────────────────────────────────────────────\n//\n// `guid` is optional. Set it for stable identity (React keys, test assertions);\n// otherwise the SDK auto-generates one at graph-build time. In token mode,\n// server-supplied steps already carry guids for analytics correlation.\n\nexport interface SurveyStep {\n type: 'survey'\n guid?: string\n title?: string\n description?: string\n reasons: ReasonConfig[]\n classNames?: SurveyClassNames\n}\n\nexport interface OfferStep {\n type: 'offer'\n guid?: string\n title?: string\n description?: string\n /**\n * Offer attached to this step. Set this to declare a standalone offer\n * step (one that isn't routed from a survey reason). `copy` is optional —\n * the SDK synthesizes default copy from the offer config when none is\n * provided, the same way it does for survey-attached offers.\n */\n offer?: OfferConfig | OfferDecision\n classNames?: OfferClassNames\n}\n\nexport interface FeedbackStep {\n type: 'feedback'\n guid?: string\n title?: string\n description?: string\n placeholder?: string\n required?: boolean\n minLength?: number\n classNames?: FeedbackClassNames\n}\n\nexport interface ConfirmStep {\n type: 'confirm'\n guid?: string\n title?: string\n description?: string\n /** Optional bullet list of what the customer is giving up. Rendered between the description and the period-end notice. */\n losses?: string[]\n /** Heading above the loss list. Defaults to \"You'll lose access to:\". */\n lossesLabel?: string\n confirmLabel?: string\n goBackLabel?: string\n classNames?: ConfirmClassNames\n}\n\nexport interface SuccessStep {\n type: 'success'\n guid?: string\n savedTitle?: string\n savedDescription?: string\n cancelledTitle?: string\n cancelledDescription?: string\n classNames?: SuccessClassNames\n}\n\nexport interface CustomStepConfig {\n type: string\n guid?: string\n title?: string\n description?: string\n data?: Record<string, unknown>\n}\n\nexport type BuiltInStep = SurveyStep | OfferStep | FeedbackStep | ConfirmStep | SuccessStep\nexport type Step = BuiltInStep | CustomStepConfig\n\nexport type BuiltInStepType = 'survey' | 'offer' | 'feedback' | 'confirm' | 'success'\n\n// ─── Per-step classNames ─────────────────────────────────────────────────────\n\nexport interface SurveyClassNames {\n root?: string\n title?: string\n description?: string\n reasonList?: string\n reasonButton?: string\n reasonButtonSelected?: string\n reasonLabel?: string\n followupInput?: string\n continueButton?: string\n}\n\nexport interface OfferClassNames {\n root?: string\n title?: string\n description?: string\n card?: string\n headline?: string\n body?: string\n acceptButton?: string\n declineButton?: string\n discountBadge?: string\n priceComparison?: string\n pauseSlider?: string\n planGrid?: string\n planCard?: string\n planCardSelected?: string\n}\n\nexport interface FeedbackClassNames {\n root?: string\n title?: string\n description?: string\n textarea?: string\n characterCount?: string\n submitButton?: string\n}\n\nexport interface ConfirmClassNames {\n root?: string\n title?: string\n description?: string\n lossList?: string\n lossLabel?: string\n lossItem?: string\n lossBullet?: string\n confirmButton?: string\n goBackButton?: string\n periodEndNotice?: string\n}\n\nexport interface SuccessClassNames {\n root?: string\n icon?: string\n title?: string\n description?: string\n closeButton?: string\n}\n\n// ─── Structural classNames ───────────────────────────────────────────────────\n\nexport interface StructuralClassNames {\n overlay?: string\n modal?: string\n closeButton?: string\n backButton?: string\n}\n\n// ─── Appearance ──────────────────────────────────────────────────────────────\n\n/**\n * Typed surface for `appearance.variables`. Every key maps to a `--ck-*`\n * CSS custom property. Consumers who need a token not in this list can\n * still set the underlying CSS variable directly — these are the ones\n * exposed through the typed JS API.\n */\nexport interface AppearanceVariables {\n // Surfaces\n colorBackground: string\n colorSurface: string\n colorSurfaceMuted: string\n\n // Borders\n colorBorder: string\n colorBorderStrong: string\n\n // Text\n colorText: string\n colorTextSecondary: string\n colorTextMuted: string\n\n // Primary\n colorPrimary: string\n colorPrimaryHover: string\n colorPrimarySoft: string\n\n // Semantic\n colorSuccess: string\n colorSuccessSoft: string\n colorDanger: string\n colorDangerHover: string\n colorDangerSoft: string\n\n // Typography\n fontFamily: string\n fontFamilyMono: string\n /**\n * Display face used by step titles and other visual headlines. Defaults\n * to `fontFamily`. Set this when your brand uses a separate display face\n * (Tiempos, Canela, etc.) for headings.\n */\n fontFamilyDisplay: string\n fontSize: string\n /** Weight applied to the step title. Default `'600'`. */\n fontWeightDisplay: string\n /** Letter spacing applied to the step title. Default `'-0.015em'`. */\n letterSpacingDisplay: string\n\n // Geometry\n borderRadius: string\n radiusSm: string\n radiusMd: string\n radiusLg: string\n radiusXl: string\n\n // Elevation\n shadowModal: string\n shadowCard: string\n\n // Overlay\n /**\n * Color of the dim behind the modal. Defaults to a neutral translucent\n * ink. Set to `color-mix(in srgb, var(--ck-color-primary) 40%, transparent)`\n * to derive the overlay from your primary color, or any CSS color value.\n */\n overlayColor: string\n}\n\nexport interface Appearance {\n /**\n * `'auto'` follows the user's OS preference (`prefers-color-scheme`) and\n * watches for changes. Default: `'light'`.\n */\n colorScheme?: 'auto' | 'light' | 'dark'\n variables?: Partial<AppearanceVariables>\n}\n\nexport interface CustomStepProps {\n step: CustomStepConfig\n customer: DirectCustomer | null\n subscriptions: DirectSubscription[]\n onNext: (result?: Record<string, unknown>) => void\n onBack: () => void\n}\n\nexport interface CustomOfferProps {\n offer: OfferDecision\n customer: DirectCustomer | null\n subscriptions: DirectSubscription[]\n onAccept: (result?: Record<string, unknown>) => Promise<void>\n onDecline: () => void\n isProcessing: boolean\n}\n\n// ─── Component overrides ─────────────────────────────────────────────────────\n\nexport interface ComponentOverrides {\n // Structural\n Modal?: (props: ModalProps) => ReactElement\n CloseButton?: (props: CloseButtonProps) => ReactElement\n BackButton?: (props: BackButtonProps) => ReactElement\n\n // Step-level (replace entire built-in step)\n Survey?: (props: SurveyStepProps) => ReactElement\n Offer?: (props: OfferStepProps) => ReactElement\n Feedback?: (props: FeedbackStepProps) => ReactElement\n Confirm?: (props: ConfirmStepProps) => ReactElement\n Success?: (props: SuccessStepProps) => ReactElement\n\n // Sub-component (replace part of a step)\n ReasonButton?: (props: ReasonButtonProps) => ReactElement\n\n // Per-type offer slots. Each owns its full canvas (title, description,\n // body, buttons) just like the step-level defaults — replacing one\n // gives full control over a single offer type. To take over offer\n // routing entirely, override `Offer` instead.\n DiscountOffer?: (props: OfferStepProps) => ReactElement\n PauseOffer?: (props: OfferStepProps) => ReactElement\n PlanChangeOffer?: (props: OfferStepProps) => ReactElement\n TrialExtensionOffer?: (props: OfferStepProps) => ReactElement\n ContactOffer?: (props: OfferStepProps) => ReactElement\n RedirectOffer?: (props: OfferStepProps) => ReactElement\n RebateOffer?: (props: OfferStepProps) => ReactElement\n}\n\nexport type CustomComponents = Record<string, ComponentType<CustomStepProps> | ComponentType<CustomOfferProps>>\n\n// ─── Structural component props ──────────────────────────────────────────────\n\nexport interface ModalProps {\n open: boolean\n onClose: () => void\n children: ReactNode\n className?: string\n overlayClassName?: string\n}\n\nexport interface CloseButtonProps {\n onClose: () => void\n className?: string\n}\n\nexport interface BackButtonProps {\n onBack: () => void\n className?: string\n}\n\n// ─── Step component props ────────────────────────────────────────────────────\n\nexport interface SurveyStepProps {\n title: string\n description?: string\n customer: DirectCustomer | null\n subscriptions: DirectSubscription[]\n reasons: ReasonConfig[]\n selectedReason: string | null\n onSelectReason: (id: string) => void\n /** Free-text value when the selected reason has `freeform: true`. Lands on the session as `followupResponse`. */\n followupResponse: string\n /** Set the follow-up response. The SDK forwards the value to the session. */\n onFollowupResponseChange: (text: string) => void\n onNext: () => void\n classNames?: SurveyClassNames\n components?: Partial<ComponentOverrides>\n}\n\nexport interface OfferStepProps {\n title?: string\n description?: string\n customer: DirectCustomer | null\n subscriptions: DirectSubscription[]\n offer: OfferDecision\n /**\n * Accept the offer. The optional `result` is included on the resulting\n * `AcceptedOffer` payload — used by offers that need a user choice (e.g.\n * `plan_change` passes `{ planId }`).\n */\n onAccept: (result?: Record<string, unknown>) => Promise<void>\n onDecline: () => void\n isProcessing: boolean\n classNames?: OfferClassNames\n /**\n * Forwarded to the default `Offer` switcher so it can dispatch to per-type\n * overrides (`DiscountOffer`, `PauseOffer`, etc). Custom `Offer`\n * implementations can ignore this.\n */\n components?: Partial<ComponentOverrides>\n}\n\nexport interface FeedbackStepProps {\n title: string\n description?: string\n customer: DirectCustomer | null\n subscriptions: DirectSubscription[]\n placeholder?: string\n required: boolean\n minLength: number\n value: string\n onChange: (text: string) => void\n onSubmit: () => void\n classNames?: FeedbackClassNames\n}\n\nexport interface ConfirmStepProps {\n title: string\n description?: string\n customer: DirectCustomer | null\n subscriptions: DirectSubscription[]\n losses?: string[]\n lossesLabel?: string\n confirmLabel: string\n goBackLabel: string\n onConfirm: () => Promise<void>\n onGoBack: () => void\n isProcessing: boolean\n classNames?: ConfirmClassNames\n}\n\nexport interface SuccessStepProps {\n outcome: 'saved' | 'cancelled'\n offer?: OfferDecision\n title: string\n description?: string\n customer: DirectCustomer | null\n subscriptions: DirectSubscription[]\n onClose: () => void\n classNames?: SuccessClassNames\n}\n\n// ─── Sub-component props ─────────────────────────────────────────────────────\n\nexport interface ReasonButtonProps {\n reason: ReasonConfig\n index: number\n isSelected: boolean\n onSelect: (id: string) => void\n}\n\n// ─── Flow state ──────────────────────────────────────────────────────────────\n\nexport interface FlowState {\n step: string\n currentStepId: string\n selectedReason: string | null\n followupResponse: string\n feedback: string\n outcome: 'saved' | 'cancelled' | null\n isProcessing: boolean\n error: Error | null\n customer: DirectCustomer | null\n subscriptions: DirectSubscription[]\n}\n\n// ─── Flow config ─────────────────────────────────────────────────────────────\n\nexport const MODES = ['live', 'test', 'sandbox'] as const\n\n/**\n * Environment a session runs against. `'test'` and `'sandbox'` both keep\n * sessions out of live analytics; `'sandbox'` additionally routes server-side\n * billing actions to the org's Stripe Sandbox credentials, which live under a\n * separate Stripe account ID from live/test mode.\n */\nexport type Mode = (typeof MODES)[number]\n\nexport interface FlowConfig extends FlowCallbacks {\n appId?: string\n customer?: DirectCustomer\n subscriptions?: DirectSubscription[]\n /**\n * Client-side attribute layer on top of provider data, e.g. usage counts\n * or entitlements only the host app knows (`{ videosCreated: 28 }`). In token mode\n * they're sent with the config request so segments can match on them when\n * picking the blueprint. In every mode they resolve as merge fields and\n * are recorded on the session, taking precedence over `customer.metadata`\n * keys. Same role as the embed's `customerAttributes`.\n */\n customerAttributes?: Record<string, unknown>\n session?: string\n apiBaseUrl?: string\n steps?: Step[]\n /**\n * Tags the session as live, test, or sandbox. Use `'test'` from staging so\n * your dashboard can filter out non-production traffic, or `'sandbox'` when\n * the org is connected to a Stripe Sandbox. Defaults to `'live'`.\n * In token mode the mode is encoded in the signed token and overrides\n * this field.\n */\n mode?: Mode\n}\n\ntype OfferCallback = (offer: AcceptedOffer, customer: DirectCustomer | null) => Promise<void> | void\ntype CancelCallback = (customer: DirectCustomer | null) => Promise<void> | void\n\n/**\n * Two kinds of callbacks, distinguished by name:\n *\n * - `handle<Type>` runs the action. When defined, it replaces whatever\n * Churnkey would do on the server — the consumer takes responsibility.\n * In local mode (no token), handlers are the only path that does anything.\n * - `on<Type>` is a listener that fires after the action. Side effects only —\n * refetch state, log analytics, show a toast. Errors thrown here are\n * swallowed; listeners can't flip the flow into an error state.\n *\n * `onAccept` is a catch-all that fires alongside the per-type listener.\n */\nexport interface FlowCallbacks {\n handleDiscount?: OfferCallback\n handlePause?: OfferCallback\n handlePlanChange?: OfferCallback\n handleTrialExtension?: OfferCallback\n handleRebate?: OfferCallback\n handleCancel?: CancelCallback\n\n onAccept?: OfferCallback\n onDiscount?: OfferCallback\n onPause?: OfferCallback\n onPlanChange?: OfferCallback\n onTrialExtension?: OfferCallback\n onRebate?: OfferCallback\n onCancel?: CancelCallback\n onClose?: () => void\n onStepChange?: (step: string, prevStep: string) => void\n}\n\n// ─── CancelFlow props ────────────────────────────────────────────────────────\n\nexport interface CancelFlowProps extends FlowCallbacks {\n appId?: string\n customer?: DirectCustomer\n subscriptions?: DirectSubscription[]\n /** See FlowConfig.customerAttributes. */\n customerAttributes?: Record<string, unknown>\n session?: string\n steps?: Step[]\n apiBaseUrl?: string\n /** See FlowConfig.mode. Ignored in token mode (the token is authoritative). */\n mode?: Mode\n appearance?: Appearance\n classNames?: StructuralClassNames\n components?: Partial<ComponentOverrides>\n customComponents?: CustomComponents\n}\n","import { MODES, type Mode } from './types'\n\nexport interface SessionCredentials {\n appId: string\n customerId: string\n subscriptionId?: string\n authHash: string\n mode: Mode\n issuedAt: number\n}\n\nfunction isMode(value: unknown): value is Mode {\n return MODES.includes(value as Mode)\n}\n\n/** Decode a session token created by `@churnkey/node`. */\nexport function decodeSessionToken(token: string): SessionCredentials {\n if (!token.startsWith('ck_')) {\n throw new Error('Invalid token: must start with \"ck_\"')\n }\n\n const encoded = token.slice(3)\n\n let json: string\n try {\n // base64url decode: replace URL-safe chars, add padding\n const base64 = encoded.replace(/-/g, '+').replace(/_/g, '/')\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4)\n json = atob(padded)\n } catch {\n throw new Error('Invalid token: malformed base64')\n }\n\n let payload: Record<string, unknown>\n try {\n payload = JSON.parse(json)\n } catch {\n throw new Error('Invalid token: malformed JSON')\n }\n\n if (typeof payload.a !== 'string' || !payload.a) {\n throw new Error('Invalid token: missing appId')\n }\n if (typeof payload.c !== 'string' || !payload.c) {\n throw new Error('Invalid token: missing customerId')\n }\n if (typeof payload.h !== 'string' || !payload.h) {\n throw new Error('Invalid token: missing authHash')\n }\n // `m` is optional and defaults to 'live'. An unrecognized value is rejected\n // rather than coerced — coercing would point test or sandbox traffic at\n // live billing data.\n const mode = payload.m === undefined ? 'live' : payload.m\n if (!isMode(mode)) {\n throw new Error(`Invalid token: unknown mode \"${String(payload.m)}\"`)\n }\n\n return {\n appId: payload.a,\n customerId: payload.c,\n subscriptionId: typeof payload.s === 'string' ? payload.s : undefined,\n authHash: payload.h,\n mode,\n issuedAt: typeof payload.t === 'number' ? payload.t : 0,\n }\n}\n"]}
|