@churnkey/react 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-CPBEP4NW.cjs → chunk-2VQNWZWO.cjs} +35 -23
- package/dist/chunk-2VQNWZWO.cjs.map +1 -0
- package/dist/{chunk-XU7KDCXO.cjs → chunk-42SJA62X.cjs} +9 -7
- package/dist/chunk-42SJA62X.cjs.map +1 -0
- package/dist/{chunk-SIYJ4R4B.cjs → chunk-LVUDBCQ2.cjs} +57 -11
- package/dist/chunk-LVUDBCQ2.cjs.map +1 -0
- package/dist/{chunk-GCQ75J4G.js → chunk-SQ35G4LA.js} +55 -11
- package/dist/chunk-SQ35G4LA.js.map +1 -0
- package/dist/{chunk-IFVMM2LB.js → chunk-UNSSI6KX.js} +35 -23
- package/dist/chunk-UNSSI6KX.js.map +1 -0
- package/dist/{chunk-QTMZI5I2.js → chunk-YZERGV7F.js} +6 -4
- package/dist/chunk-YZERGV7F.js.map +1 -0
- package/dist/core.cjs +20 -12
- package/dist/core.d.cts +14 -3
- package/dist/core.d.ts +14 -3
- package/dist/core.js +2 -2
- package/dist/headless.cjs +3 -3
- package/dist/headless.d.cts +5 -1
- package/dist/headless.d.ts +5 -1
- package/dist/headless.js +2 -2
- package/dist/index.cjs +199 -189
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +116 -114
- package/dist/index.js.map +1 -1
- package/dist/{step-graph-ChdI-VXV.d.ts → step-graph-ChlSCUGk.d.cts} +89 -20
- package/dist/{step-graph-ChdI-VXV.d.cts → step-graph-ChlSCUGk.d.ts} +89 -20
- package/dist/styles.css +173 -67
- package/package.json +1 -1
- package/dist/chunk-CPBEP4NW.cjs.map +0 -1
- package/dist/chunk-GCQ75J4G.js.map +0 -1
- package/dist/chunk-IFVMM2LB.js.map +0 -1
- package/dist/chunk-QTMZI5I2.js.map +0 -1
- package/dist/chunk-SIYJ4R4B.cjs.map +0 -1
- package/dist/chunk-XU7KDCXO.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -177,7 +177,7 @@ The hook returns the current state (`step`, `reasons`, `currentOffer`, `feedback
|
|
|
177
177
|
|
|
178
178
|
## Add analytics
|
|
179
179
|
|
|
180
|
-
Create a free account
|
|
180
|
+
Create a [free Churnkey account](https://app.churnkey.co/register?intent=sdk) and pass your `appId`. The SDK records each session so you can see why customers cancel, which offers work, and what your save rate looks like.
|
|
181
181
|
|
|
182
182
|
```tsx
|
|
183
183
|
<CancelFlow
|
|
@@ -156,7 +156,7 @@ function mergeStep(step, attrs) {
|
|
|
156
156
|
...s,
|
|
157
157
|
title: maybeMerge(s.title, attrs),
|
|
158
158
|
description: maybeMerge(s.description, attrs),
|
|
159
|
-
offer: s.offer ?
|
|
159
|
+
offer: s.offer ? mergeOffer(s.offer, attrs) : void 0
|
|
160
160
|
};
|
|
161
161
|
}
|
|
162
162
|
case "feedback": {
|
|
@@ -179,7 +179,8 @@ function mergeStep(step, attrs) {
|
|
|
179
179
|
function mergeReason(r, attrs) {
|
|
180
180
|
return { ...r, label: applyMergeFields(r.label, attrs) };
|
|
181
181
|
}
|
|
182
|
-
function
|
|
182
|
+
function mergeOffer(o, attrs) {
|
|
183
|
+
if (!("copy" in o)) return o;
|
|
183
184
|
return {
|
|
184
185
|
...o,
|
|
185
186
|
copy: {
|
|
@@ -198,7 +199,7 @@ function maybeMerge(text, attrs) {
|
|
|
198
199
|
var EMPTY_GRAPH = { stepMap: {}, firstStepId: "", orderedStepIds: [] };
|
|
199
200
|
function buildStepGraph(steps, defaultOfferCopy2) {
|
|
200
201
|
if (steps.length === 0) return EMPTY_GRAPH;
|
|
201
|
-
const resolved = steps.map((step, i) => normalizeStep(step, i));
|
|
202
|
+
const resolved = steps.map((step, i) => normalizeStep(step, i, defaultOfferCopy2));
|
|
202
203
|
linkNeighbors(resolved);
|
|
203
204
|
const stepMap = {};
|
|
204
205
|
for (const step of resolved) stepMap[step.guid] = step;
|
|
@@ -228,7 +229,7 @@ function buildStepGraph(steps, defaultOfferCopy2) {
|
|
|
228
229
|
surveyStepId: surveyStep?.guid
|
|
229
230
|
};
|
|
230
231
|
}
|
|
231
|
-
function normalizeStep(step, index) {
|
|
232
|
+
function normalizeStep(step, index, defaultOfferCopy2) {
|
|
232
233
|
const guid = step.guid ?? `step-${index}-${step.type}`;
|
|
233
234
|
const base = { guid, type: step.type };
|
|
234
235
|
switch (step.type) {
|
|
@@ -249,7 +250,10 @@ function normalizeStep(step, index) {
|
|
|
249
250
|
...base,
|
|
250
251
|
title: s.title,
|
|
251
252
|
description: s.description,
|
|
252
|
-
|
|
253
|
+
// Standalone offers may arrive without `copy` — toDecision fills it
|
|
254
|
+
// in from defaultOfferCopy. Token-mode offers already carry copy
|
|
255
|
+
// from the server, so toDecision passes them through unchanged.
|
|
256
|
+
offer: s.offer ? toDecision(s.offer, defaultOfferCopy2) : void 0,
|
|
253
257
|
classNames: s.classNames
|
|
254
258
|
};
|
|
255
259
|
}
|
|
@@ -271,6 +275,8 @@ function normalizeStep(step, index) {
|
|
|
271
275
|
...base,
|
|
272
276
|
title: s.title,
|
|
273
277
|
description: s.description,
|
|
278
|
+
losses: s.losses,
|
|
279
|
+
lossesLabel: s.lossesLabel,
|
|
274
280
|
classNames: s.classNames
|
|
275
281
|
};
|
|
276
282
|
}
|
|
@@ -356,9 +362,9 @@ function transformStep(step) {
|
|
|
356
362
|
function transformReason(r) {
|
|
357
363
|
const out = {
|
|
358
364
|
id: r.id,
|
|
359
|
-
label: r.label
|
|
360
|
-
freeform: r.freeform
|
|
365
|
+
label: r.label
|
|
361
366
|
};
|
|
367
|
+
if (r.freeform) out.freeform = true;
|
|
362
368
|
if (r.offer) out.offer = transformOfferConfig(r.offer);
|
|
363
369
|
return out;
|
|
364
370
|
}
|
|
@@ -382,8 +388,7 @@ function transformOfferConfig(o) {
|
|
|
382
388
|
return {
|
|
383
389
|
type: "pause",
|
|
384
390
|
months: o.months,
|
|
385
|
-
interval: o.interval
|
|
386
|
-
datePicker: o.datePicker
|
|
391
|
+
interval: o.interval
|
|
387
392
|
};
|
|
388
393
|
case "plan_change":
|
|
389
394
|
return {
|
|
@@ -642,7 +647,7 @@ var CancelFlowMachine = class {
|
|
|
642
647
|
const merged = applyMergeFieldsToSteps(config.steps, this.directCustomer);
|
|
643
648
|
this.graph = buildStepGraph(merged, defaultOfferCopy);
|
|
644
649
|
}
|
|
645
|
-
this.state = this.buildInitialState(
|
|
650
|
+
this.state = this.buildInitialState(this.directCustomer, this.directSubscriptions ?? []);
|
|
646
651
|
this.cachedSnapshot = { ...this.state };
|
|
647
652
|
const first = this.firstStep();
|
|
648
653
|
if (!config.session && first) this.trackStepEnter(first);
|
|
@@ -696,7 +701,10 @@ var CancelFlowMachine = class {
|
|
|
696
701
|
}
|
|
697
702
|
selectReason = (id) => {
|
|
698
703
|
if (!this.reasons.find((r) => r.id === id)) return;
|
|
699
|
-
this.setState({ selectedReason: id });
|
|
704
|
+
this.setState({ selectedReason: id, followupResponse: "" });
|
|
705
|
+
};
|
|
706
|
+
setFollowupResponse = (text) => {
|
|
707
|
+
this.setState({ followupResponse: text });
|
|
700
708
|
};
|
|
701
709
|
next = (result) => {
|
|
702
710
|
if (isPlainObject(result)) {
|
|
@@ -784,7 +792,7 @@ var CancelFlowMachine = class {
|
|
|
784
792
|
const merged = this.localSteps ? mergeLocalSteps(result.steps, this.localSteps) : result.steps;
|
|
785
793
|
const steps = applyMergeFieldsToSteps(merged, config.customer ?? null);
|
|
786
794
|
this.graph = buildStepGraph(steps, defaultOfferCopy);
|
|
787
|
-
this.state = this.buildInitialState(config.customer ?? null);
|
|
795
|
+
this.state = this.buildInitialState(config.customer ?? null, config.subscriptions ?? []);
|
|
788
796
|
this.cachedSnapshot = { ...this.state };
|
|
789
797
|
const first = this.firstStep();
|
|
790
798
|
if (first) this.trackStepEnter(first);
|
|
@@ -800,17 +808,19 @@ var CancelFlowMachine = class {
|
|
|
800
808
|
surveyStep() {
|
|
801
809
|
return this.graph.surveyStepId ? this.graph.stepMap[this.graph.surveyStepId] : void 0;
|
|
802
810
|
}
|
|
803
|
-
buildInitialState(customer) {
|
|
811
|
+
buildInitialState(customer, subscriptions) {
|
|
804
812
|
const first = this.firstStep();
|
|
805
813
|
return {
|
|
806
814
|
step: first?.type ?? "survey",
|
|
807
815
|
currentStepId: this.graph.firstStepId,
|
|
808
816
|
selectedReason: null,
|
|
817
|
+
followupResponse: "",
|
|
809
818
|
feedback: "",
|
|
810
819
|
outcome: null,
|
|
811
820
|
isProcessing: false,
|
|
812
821
|
error: null,
|
|
813
|
-
customer
|
|
822
|
+
customer,
|
|
823
|
+
subscriptions
|
|
814
824
|
};
|
|
815
825
|
}
|
|
816
826
|
// On a survey step with a selected reason that has an attached offer,
|
|
@@ -921,14 +931,14 @@ var CancelFlowMachine = class {
|
|
|
921
931
|
}
|
|
922
932
|
}
|
|
923
933
|
// Offer passed in so accept() can capture it before enterSuccessStep
|
|
924
|
-
// potentially moves currentStepId off the offer step.
|
|
934
|
+
// potentially moves currentStepId off the offer step. copy and decisionId
|
|
935
|
+
// are SDK-internal — strip them from the consumer-facing payload.
|
|
925
936
|
buildAcceptedOffer(offer, result) {
|
|
926
|
-
const { copy:
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
};
|
|
937
|
+
const { copy: _copy, decisionId: _decisionId, ...offerConfig } = offer;
|
|
938
|
+
const accepted = offerConfig;
|
|
939
|
+
if (this.state.selectedReason) accepted.reasonId = this.state.selectedReason;
|
|
940
|
+
if (result) accepted.result = result;
|
|
941
|
+
return accepted;
|
|
932
942
|
}
|
|
933
943
|
// Terminal transition. Prefer moving currentStepId to a declared success
|
|
934
944
|
// step so the developer's savedTitle / classNames / custom component
|
|
@@ -948,12 +958,14 @@ var CancelFlowMachine = class {
|
|
|
948
958
|
}
|
|
949
959
|
buildBasePayload() {
|
|
950
960
|
const selectedReason = this.reasons.find((r) => r.id === this.state.selectedReason);
|
|
961
|
+
const followupResponse = selectedReason?.freeform && this.state.followupResponse ? this.state.followupResponse : void 0;
|
|
951
962
|
const payload = {
|
|
952
963
|
blueprintId: this.blueprintId ?? void 0,
|
|
953
964
|
customer: this.resolveSessionCustomer(),
|
|
954
965
|
canceled: false,
|
|
955
966
|
surveyChoiceId: this.state.selectedReason ?? void 0,
|
|
956
967
|
surveyChoiceValue: selectedReason?.label,
|
|
968
|
+
followupResponse,
|
|
957
969
|
feedback: this.state.feedback || void 0,
|
|
958
970
|
presentedOffers: this.presentedOffers,
|
|
959
971
|
stepsViewed: this.stepsViewed,
|
|
@@ -1055,5 +1067,5 @@ exports.AnalyticsClient = AnalyticsClient;
|
|
|
1055
1067
|
exports.CancelFlowMachine = CancelFlowMachine;
|
|
1056
1068
|
exports.ChurnkeyApi = ChurnkeyApi;
|
|
1057
1069
|
exports.decodeSessionToken = decodeSessionToken;
|
|
1058
|
-
//# sourceMappingURL=chunk-
|
|
1059
|
-
//# sourceMappingURL=chunk-
|
|
1070
|
+
//# sourceMappingURL=chunk-2VQNWZWO.cjs.map
|
|
1071
|
+
//# sourceMappingURL=chunk-2VQNWZWO.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/api.ts","../src/core/merge-fields.ts","../src/core/step-graph.ts","../src/core/transform.ts","../src/core/machine.ts","../src/core/token.ts"],"names":["defaultOfferCopy"],"mappings":"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","file":"chunk-2VQNWZWO.cjs","sourcesContent":["import type { SdkConfig } from './api-types'\nimport type { SessionCredentials } from './token'\nimport type { DirectCustomer, DirectSubscription } 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 = 'DISCOUNT' | 'PAUSE' | 'PLAN_CHANGE' | 'TRIAL_EXTENSION' | 'CONTACT' | 'REDIRECT' | 'CUSTOM'\nexport type ApiPauseInterval = 'MONTH' | 'WEEK'\nexport type ApiCouponType = 'PERCENT' | 'AMOUNT'\nexport type ApiBillingInterval = 'DAY' | 'WEEK' | 'MONTH' | 'YEAR'\nexport type ApiMode = 'LIVE' | 'TEST'\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}\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 async fetchConfig(): Promise<SdkConfig> {\n const res = await this.request(this.orgUrl('cancel-flow/config'))\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 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. Values that aren't strings are coerced — dashboards emit merge\n * fields into HTML, and HTML only speaks strings.\n */\nexport function buildMergeAttrs(customer: DirectCustomer | null | undefined): MergeAttrs {\n if (!customer) return {}\n const attrs: MergeAttrs = {}\n\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 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(steps: Step[], customer: DirectCustomer | null | undefined): Step[] {\n const attrs = buildMergeAttrs(customer)\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, SdkDiscountOffer, SdkOffer, SdkReason, SdkStep } from './api-types'\nimport type { BuiltInOfferConfig, OfferConfig, OfferCopy, OfferDecision, ReasonConfig, Step } from './types'\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 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 }\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 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 } 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 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 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 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}\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 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 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: 'live' | 'test' = '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.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)\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)\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)\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): 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 }\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 // 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, id: this.creds.customerId, subscriptionId: this.creds.subscriptionId }\n }\n return direct\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: (this.creds?.mode ?? this.configMode) === 'test' ? 'TEST' : 'LIVE',\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","export interface SessionCredentials {\n appId: string\n customerId: string\n subscriptionId?: string\n authHash: string\n mode: 'live' | 'test'\n issuedAt: number\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\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: payload.m === 'test' ? 'test' : 'live',\n issuedAt: typeof payload.t === 'number' ? payload.t : 0,\n }\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk2VQNWZWO_cjs = require('./chunk-2VQNWZWO.cjs');
|
|
4
4
|
var react = require('react');
|
|
5
5
|
|
|
6
6
|
function useCancelFlowMachine(config) {
|
|
@@ -23,7 +23,7 @@ function useCancelFlowMachine(config) {
|
|
|
23
23
|
onClose: () => cb.current.onClose?.(),
|
|
24
24
|
onStepChange: (step, prevStep) => cb.current.onStepChange?.(step, prevStep)
|
|
25
25
|
};
|
|
26
|
-
return new
|
|
26
|
+
return new chunk2VQNWZWO_cjs.CancelFlowMachine({ ...config, ...dispatch });
|
|
27
27
|
});
|
|
28
28
|
const [state, setState] = react.useState(() => machine.getSnapshot());
|
|
29
29
|
const [isLoading, setIsLoading] = react.useState(!!config.session);
|
|
@@ -37,8 +37,8 @@ function useCancelFlowMachine(config) {
|
|
|
37
37
|
setLoadError(null);
|
|
38
38
|
setIsLoading(true);
|
|
39
39
|
let cancelled = false;
|
|
40
|
-
const creds =
|
|
41
|
-
const api = new
|
|
40
|
+
const creds = chunk2VQNWZWO_cjs.decodeSessionToken(config.session);
|
|
41
|
+
const api = new chunk2VQNWZWO_cjs.ChurnkeyApi(creds, config.apiBaseUrl);
|
|
42
42
|
api.fetchConfig().then((sdkConfig) => {
|
|
43
43
|
if (cancelled) return;
|
|
44
44
|
machine.initializeFromConfig(sdkConfig, api, creds);
|
|
@@ -61,17 +61,19 @@ function useCancelFlowMachine(config) {
|
|
|
61
61
|
|
|
62
62
|
// src/headless/use-cancel-flow.ts
|
|
63
63
|
function useCancelFlow(config) {
|
|
64
|
-
const { machine, state, isLoading, loadError } = useCancelFlowMachine(config);
|
|
64
|
+
const { machine, state, isLoading, loadError, retry } = useCancelFlowMachine(config);
|
|
65
65
|
return {
|
|
66
66
|
...state,
|
|
67
67
|
isLoading,
|
|
68
68
|
loadError,
|
|
69
|
+
retry,
|
|
69
70
|
reasons: machine.reasons,
|
|
70
71
|
currentStep: machine.currentStep,
|
|
71
72
|
currentOffer: machine.currentOffer,
|
|
72
73
|
stepIndex: machine.stepIndex,
|
|
73
74
|
totalSteps: machine.totalSteps,
|
|
74
75
|
selectReason: machine.selectReason,
|
|
76
|
+
setFollowupResponse: machine.setFollowupResponse,
|
|
75
77
|
setFeedback: machine.setFeedback,
|
|
76
78
|
accept: machine.accept,
|
|
77
79
|
decline: machine.decline,
|
|
@@ -84,5 +86,5 @@ function useCancelFlow(config) {
|
|
|
84
86
|
|
|
85
87
|
exports.useCancelFlow = useCancelFlow;
|
|
86
88
|
exports.useCancelFlowMachine = useCancelFlowMachine;
|
|
87
|
-
//# sourceMappingURL=chunk-
|
|
88
|
-
//# sourceMappingURL=chunk-
|
|
89
|
+
//# sourceMappingURL=chunk-42SJA62X.cjs.map
|
|
90
|
+
//# sourceMappingURL=chunk-42SJA62X.cjs.map
|
|
@@ -0,0 +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-42SJA62X.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 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 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 .fetchConfig()\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"]}
|
|
@@ -52,12 +52,20 @@ function formatPriceFromMinor(value, currency = "USD", locale) {
|
|
|
52
52
|
function calculateDiscountedPrice(originalPrice, percentOff) {
|
|
53
53
|
return originalPrice * (1 - percentOff / 100);
|
|
54
54
|
}
|
|
55
|
-
function formatShortDate(date, locale) {
|
|
56
|
-
return date.toLocaleDateString(locale, { month: "short", day: "numeric", year: "numeric" });
|
|
57
|
-
}
|
|
58
55
|
function formatMonthDay(date, locale) {
|
|
59
56
|
return date.toLocaleDateString(locale, { month: "short", day: "numeric" });
|
|
60
57
|
}
|
|
58
|
+
function formatMonthDayLong(date, locale) {
|
|
59
|
+
return date.toLocaleDateString(locale, { month: "long", day: "numeric" });
|
|
60
|
+
}
|
|
61
|
+
function formatPeriodEnd(subscriptions, locale) {
|
|
62
|
+
const status = subscriptions?.[0]?.status;
|
|
63
|
+
if (!status || !("currentPeriod" in status) || !status.currentPeriod?.end) return null;
|
|
64
|
+
const end = status.currentPeriod.end;
|
|
65
|
+
const d = end instanceof Date ? end : new Date(end);
|
|
66
|
+
if (Number.isNaN(d.getTime())) return null;
|
|
67
|
+
return d.toLocaleDateString(locale, { month: "long", day: "numeric", year: "numeric" });
|
|
68
|
+
}
|
|
61
69
|
function discountPhrase(opts) {
|
|
62
70
|
const { percentOff, amountOff, currency, duration, durationInMonths } = opts;
|
|
63
71
|
const amount = percentOff != null ? `${percentOff}% off` : amountOff != null ? `${formatPriceFromMinor(amountOff, currency)} off` : "discount";
|
|
@@ -67,21 +75,57 @@ function discountPhrase(opts) {
|
|
|
67
75
|
|
|
68
76
|
// src/core/utils.ts
|
|
69
77
|
var BUILT_IN_STEP_TYPES = ["survey", "offer", "feedback", "confirm", "success"];
|
|
78
|
+
var BUILT_IN_OFFER_TYPES = [
|
|
79
|
+
"discount",
|
|
80
|
+
"pause",
|
|
81
|
+
"trial_extension",
|
|
82
|
+
"plan_change",
|
|
83
|
+
"contact",
|
|
84
|
+
"redirect"
|
|
85
|
+
];
|
|
70
86
|
function cn(...classes) {
|
|
71
87
|
return classes.filter(Boolean).join(" ");
|
|
72
88
|
}
|
|
73
89
|
var VAR_MAP = {
|
|
74
|
-
|
|
75
|
-
"--ck-color-primary-hover": "colorPrimaryHover",
|
|
90
|
+
// Surfaces
|
|
76
91
|
"--ck-color-bg": "colorBackground",
|
|
92
|
+
"--ck-color-surface": "colorSurface",
|
|
93
|
+
"--ck-color-surface-muted": "colorSurfaceMuted",
|
|
94
|
+
// Borders
|
|
95
|
+
"--ck-color-border": "colorBorder",
|
|
96
|
+
"--ck-color-border-strong": "colorBorderStrong",
|
|
97
|
+
// Text
|
|
77
98
|
"--ck-color-text": "colorText",
|
|
78
99
|
"--ck-color-text-secondary": "colorTextSecondary",
|
|
79
|
-
"--ck-color-
|
|
80
|
-
|
|
100
|
+
"--ck-color-text-muted": "colorTextMuted",
|
|
101
|
+
// Primary
|
|
102
|
+
"--ck-color-primary": "colorPrimary",
|
|
103
|
+
"--ck-color-primary-hover": "colorPrimaryHover",
|
|
104
|
+
"--ck-color-primary-soft": "colorPrimarySoft",
|
|
105
|
+
// Semantic
|
|
81
106
|
"--ck-color-success": "colorSuccess",
|
|
107
|
+
"--ck-color-success-soft": "colorSuccessSoft",
|
|
108
|
+
"--ck-color-danger": "colorDanger",
|
|
109
|
+
"--ck-color-danger-hover": "colorDangerHover",
|
|
110
|
+
"--ck-color-danger-soft": "colorDangerSoft",
|
|
111
|
+
// Typography
|
|
82
112
|
"--ck-font-family": "fontFamily",
|
|
113
|
+
"--ck-font-mono": "fontFamilyMono",
|
|
114
|
+
"--ck-font-display": "fontFamilyDisplay",
|
|
83
115
|
"--ck-font-size": "fontSize",
|
|
84
|
-
"--ck-
|
|
116
|
+
"--ck-step-title-weight": "fontWeightDisplay",
|
|
117
|
+
"--ck-step-title-letter-spacing": "letterSpacingDisplay",
|
|
118
|
+
// Geometry
|
|
119
|
+
"--ck-border-radius": "borderRadius",
|
|
120
|
+
"--ck-radius-sm": "radiusSm",
|
|
121
|
+
"--ck-radius-md": "radiusMd",
|
|
122
|
+
"--ck-radius-lg": "radiusLg",
|
|
123
|
+
"--ck-radius-xl": "radiusXl",
|
|
124
|
+
// Elevation
|
|
125
|
+
"--ck-shadow-modal": "shadowModal",
|
|
126
|
+
"--ck-shadow-card": "shadowCard",
|
|
127
|
+
// Overlay
|
|
128
|
+
"--ck-overlay-color": "overlayColor"
|
|
85
129
|
};
|
|
86
130
|
function appearanceToStyle(appearance) {
|
|
87
131
|
const variables = appearance?.variables;
|
|
@@ -99,6 +143,7 @@ var defaultTitles = {
|
|
|
99
143
|
confirm: "Confirm cancellation"
|
|
100
144
|
};
|
|
101
145
|
|
|
146
|
+
exports.BUILT_IN_OFFER_TYPES = BUILT_IN_OFFER_TYPES;
|
|
102
147
|
exports.BUILT_IN_STEP_TYPES = BUILT_IN_STEP_TYPES;
|
|
103
148
|
exports.appearanceToStyle = appearanceToStyle;
|
|
104
149
|
exports.calculateDiscountedPrice = calculateDiscountedPrice;
|
|
@@ -106,8 +151,9 @@ exports.cn = cn;
|
|
|
106
151
|
exports.defaultTitles = defaultTitles;
|
|
107
152
|
exports.discountPhrase = discountPhrase;
|
|
108
153
|
exports.formatMonthDay = formatMonthDay;
|
|
154
|
+
exports.formatMonthDayLong = formatMonthDayLong;
|
|
155
|
+
exports.formatPeriodEnd = formatPeriodEnd;
|
|
109
156
|
exports.formatPrice = formatPrice;
|
|
110
157
|
exports.formatPriceFromMinor = formatPriceFromMinor;
|
|
111
|
-
|
|
112
|
-
//# sourceMappingURL=chunk-
|
|
113
|
-
//# sourceMappingURL=chunk-SIYJ4R4B.cjs.map
|
|
158
|
+
//# sourceMappingURL=chunk-LVUDBCQ2.cjs.map
|
|
159
|
+
//# sourceMappingURL=chunk-LVUDBCQ2.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/format.ts","../src/core/utils.ts"],"names":[],"mappings":"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","file":"chunk-LVUDBCQ2.cjs","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","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]\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"]}
|