@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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-CPBEP4NW.cjs → chunk-2VQNWZWO.cjs} +35 -23
  3. package/dist/chunk-2VQNWZWO.cjs.map +1 -0
  4. package/dist/{chunk-XU7KDCXO.cjs → chunk-42SJA62X.cjs} +9 -7
  5. package/dist/chunk-42SJA62X.cjs.map +1 -0
  6. package/dist/{chunk-SIYJ4R4B.cjs → chunk-LVUDBCQ2.cjs} +57 -11
  7. package/dist/chunk-LVUDBCQ2.cjs.map +1 -0
  8. package/dist/{chunk-GCQ75J4G.js → chunk-SQ35G4LA.js} +55 -11
  9. package/dist/chunk-SQ35G4LA.js.map +1 -0
  10. package/dist/{chunk-IFVMM2LB.js → chunk-UNSSI6KX.js} +35 -23
  11. package/dist/chunk-UNSSI6KX.js.map +1 -0
  12. package/dist/{chunk-QTMZI5I2.js → chunk-YZERGV7F.js} +6 -4
  13. package/dist/chunk-YZERGV7F.js.map +1 -0
  14. package/dist/core.cjs +20 -12
  15. package/dist/core.d.cts +14 -3
  16. package/dist/core.d.ts +14 -3
  17. package/dist/core.js +2 -2
  18. package/dist/headless.cjs +3 -3
  19. package/dist/headless.d.cts +5 -1
  20. package/dist/headless.d.ts +5 -1
  21. package/dist/headless.js +2 -2
  22. package/dist/index.cjs +199 -189
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +7 -7
  25. package/dist/index.d.ts +7 -7
  26. package/dist/index.js +116 -114
  27. package/dist/index.js.map +1 -1
  28. package/dist/{step-graph-ChdI-VXV.d.ts → step-graph-ChlSCUGk.d.cts} +89 -20
  29. package/dist/{step-graph-ChdI-VXV.d.cts → step-graph-ChlSCUGk.d.ts} +89 -20
  30. package/dist/styles.css +173 -67
  31. package/package.json +1 -1
  32. package/dist/chunk-CPBEP4NW.cjs.map +0 -1
  33. package/dist/chunk-GCQ75J4G.js.map +0 -1
  34. package/dist/chunk-IFVMM2LB.js.map +0 -1
  35. package/dist/chunk-QTMZI5I2.js.map +0 -1
  36. package/dist/chunk-SIYJ4R4B.cjs.map +0 -1
  37. 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 at [churnkey.co](https://churnkey.co) and pass your app ID. The SDK records each session so you can see why customers cancel, which offers work, and what your save rate looks like.
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 ? mergeOfferDecision(s.offer, attrs) : void 0
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 mergeOfferDecision(o, attrs) {
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
- offer: s.offer,
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(null);
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: _, ...offerConfig } = offer;
927
- return {
928
- ...offerConfig,
929
- reasonId: this.state.selectedReason,
930
- ...result ? { result } : {}
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-CPBEP4NW.cjs.map
1059
- //# sourceMappingURL=chunk-CPBEP4NW.cjs.map
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 chunkCPBEP4NW_cjs = require('./chunk-CPBEP4NW.cjs');
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 chunkCPBEP4NW_cjs.CancelFlowMachine({ ...config, ...dispatch });
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 = chunkCPBEP4NW_cjs.decodeSessionToken(config.session);
41
- const api = new chunkCPBEP4NW_cjs.ChurnkeyApi(creds, config.apiBaseUrl);
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-XU7KDCXO.cjs.map
88
- //# sourceMappingURL=chunk-XU7KDCXO.cjs.map
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
- "--ck-color-primary": "colorPrimary",
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-border": "colorBorder",
80
- "--ck-color-danger": "colorDanger",
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-border-radius": "borderRadius"
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
- exports.formatShortDate = formatShortDate;
112
- //# sourceMappingURL=chunk-SIYJ4R4B.cjs.map
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"]}